private IEnumerator OnOffer(RTCSessionDescription desc) { Debug.Log("OnOffer"); Debug.Log("SetRemoteDescription start"); var op = pc.SetRemoteDescription(ref desc); yield return(op); if (!op.IsError) { Debug.Log("SetRemoteDescription succeed"); } else { Debug.Log("SetLocalDescription failed"); } var op1 = pc.CreateAnswer(ref _answerOptions); yield return(op1); if (!op1.IsError) { Debug.Log("CreateAnswer succeed"); yield return(OnCreateAnswerSuccess(op1.Desc)); } else { Debug.Log("CreateAnswer failed"); } }
public IEnumerator CreateAnswer() { var config = GetDefaultConfiguration(); var peer1 = new RTCPeerConnection(ref config); var peer2 = new RTCPeerConnection(ref config); peer1.CreateDataChannel("data"); var op1 = peer1.CreateOffer(); 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(); yield return(op4); Assert.True(op4.IsDone); Assert.False(op4.IsError); peer1.Close(); peer2.Close(); peer1.Dispose(); peer2.Dispose(); }
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); }
IEnumerator SendAnswerCoroutine(string connectionId, RTCPeerConnection pc) { RTCAnswerOptions options = default; var op = pc.CreateAnswer(ref options); yield return(op); if (op.IsError) { Debug.LogError($"Network Error: {op.Error.message}"); yield break; } var desc = op.Desc; var opLocalDesc = pc.SetLocalDescription(ref desc); yield return(opLocalDesc); if (opLocalDesc.IsError) { Debug.LogError($"Network Error: {opLocalDesc.Error.message}"); yield break; } _signaling.SendAnswer(connectionId, desc); }
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(); }
IEnumerator Negotiate(RTCPeerConnection peer1, RTCPeerConnection peer2) { if (negotiating) { Debug.LogError("Negotiating"); yield break; } negotiating = true; var op1 = peer1.CreateOffer(); yield return(op1); Assert.That(op1.IsError, Is.False, op1.Error.message); var desc = op1.Desc; var op2 = peer1.SetLocalDescription(ref desc); yield return(op2); Assert.That(op2.IsError, Is.False, op2.Error.message); var op3 = peer2.SetRemoteDescription(ref desc); yield return(op3); Assert.That(op3.IsError, Is.False, op3.Error.message); var op4 = peer2.CreateAnswer(); yield return(op4); Assert.That(op4.IsError, Is.False, op4.Error.message); desc = op4.Desc; var op5 = peer2.SetLocalDescription(ref desc); yield return(op5); Assert.That(op5.IsError, Is.False, op5.Error.message); var op6 = peer1.SetRemoteDescription(ref desc); yield return(op6); Assert.That(op6.IsError, Is.False, op6.Error.message); var op7 = new WaitUntilWithTimeout(() => peers[0].SignalingState == RTCSignalingState.Stable && peers[1].SignalingState == RTCSignalingState.Stable, 5000); yield return(op7); Assert.That(op7.IsCompleted, Is.True); IsTestFinished = true; negotiating = false; }
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); }
IEnumerator OnOffer(ISignaling signaling, DescData e) { var connectionId = e.connectionId; RTCPeerConnection pc = null; if (!m_mapConnectionIdAndPeer.TryGetValue(connectionId, out pc)) { pc = CreatePeerConnection(signaling, connectionId, false); } RTCSessionDescription _desc; _desc.type = RTCSdpType.Offer; _desc.sdp = e.sdp; var opRemoteDesc = pc.SetRemoteDescription(ref _desc); yield return(opRemoteDesc); if (opRemoteDesc.IsError) { Debug.LogError($"Network Error: {opRemoteDesc.Error.message}"); yield break; } AddTracks(connectionId, pc); RTCAnswerOptions options = default; var op = pc.CreateAnswer(ref options); yield return(op); if (op.IsError) { Debug.LogError($"Network Error: {op.Error.message}"); yield break; } var desc = op.Desc; var opLocalDesc = pc.SetLocalDescription(ref desc); yield return(opLocalDesc); if (opLocalDesc.IsError) { Debug.LogError($"Network Error: {opLocalDesc.Error.message}"); yield break; } signaling.SendAnswer(connectionId, desc); }
private IEnumerator sendDesc(RTCSdpType type) { RTCSessionDescriptionAsyncOperation opCreate = null; if (type == RTCSdpType.Offer) { OnLogEvent.Invoke("CreateOffer()", ""); opCreate = peer.CreateOffer(ref offerOption); } else { OnLogEvent.Invoke("CreateAnswer()", ""); opCreate = peer.CreateAnswer(ref answerOptions); } yield return(opCreate); if (opCreate.IsError) { OnErrorEvent.Invoke($"Create {opCreate.Desc.type}", opCreate.Error.message); yield break; } else { OnLogEvent.Invoke($"Create {opCreate.Desc.type}", ""); } if (opCreate.Desc.sdp == null) { OnErrorEvent.Invoke("opCreate.Desc.sdp is null", ""); yield break; } else { OnLogEvent.Invoke($"SetLocalDescription {type}", $"{opCreate.Desc.sdp.Substring(0, 10)} ..."); } var desc = opCreate.Desc; var opSet = peer.SetLocalDescription(ref desc); yield return(opSet); if (opSet.IsError) { OnErrorEvent.Invoke($"SetLocalDescription {type}", opSet.Error.message); yield break; } OnLogEvent.Invoke($"Send {type}", ""); signaling.SendDesc(streamId, desc.type.ToString().ToLower(), desc.sdp); }
private IEnumerator createDesc(RTCSdpType type) { RTCSessionDescriptionAsyncOperation opCreate; if (type == RTCSdpType.Offer) { opCreate = peer.CreateOffer(ref offerOptions); } else { opCreate = peer.CreateAnswer(ref answerOptions); } yield return(opCreate); if (opCreate.IsError) { log(LogLevel.Error, $"Create {opCreate.Desc.type}: {opCreate.Error.message}"); yield break; } else { log(LogLevel.Log, $"Create {opCreate.Desc.type}"); } if (opCreate.Desc.sdp == null) { log(LogLevel.Error, $"opCreate.Desc.sdp is null"); yield break; } else { log(LogLevel.Log, $"SetLocalDescription {type}: {opCreate.Desc.sdp}"); } var desc = opCreate.Desc; var opSet = peer.SetLocalDescription(ref desc); yield return(opSet); if (opSet.IsError) { log(LogLevel.Error, $"SetLocalDescription {type}: {opSet.Error.message}"); yield break; } log(LogLevel.Log, $">>> Send \"takeConfiguration\" Command ({type}: '{desc.sdp.Substring(0, 10)} ...')"); signaling.SendDesc(streamId, desc.type.ToString().ToLower(), desc.sdp); }
private async void NewElement_AnswerRequested(object sender, SdpEventArgs e) { await _peerConnection.SetRemoteDescription(e.Sdp.ToRTCSessionDescription()); Debug.WriteLine("AnswerRequested SetRemoteDescription complete"); var answerDesc = await _peerConnection.CreateAnswer(); Debug.WriteLine("AnswerRequested CreateAnswer complete"); await _peerConnection.SetLocalDescription(answerDesc); Debug.WriteLine("AnswerRequested SetLocalDescription complete"); Element.SendAnswerRecived(answerDesc.ToWebRTCSDP()); }
IEnumerator CreateAnswer() { Debug.Log("CreateAnswer start"); var op = peerConnection.CreateAnswer(ref _answerOptions); yield return(op); if (!op.IsError) { yield return(StartCoroutine(OnCreateAnswerSuccess(op.Desc))); } else { OnCreateSessionDescriptionError(op.Error); } }
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 IEnumerator CreateAnswerFailed() { var config = GetConfiguration(); var peer = new RTCPeerConnection(ref config); RTCAnswerOptions options = default; var op = peer.CreateAnswer(ref options); yield return(op); Assert.True(op.IsDone); // This is failed Assert.True(op.IsError); peer.Close(); peer.Dispose(); }
public IEnumerator CreateAnswerFailed() { var config = GetDefaultConfiguration(); var peer = new RTCPeerConnection(ref config); var op = peer.CreateAnswer(); yield return(op); Assert.True(op.IsDone); // This is failed Assert.True(op.IsError); Assert.IsNotEmpty(op.Error.message); peer.Close(); peer.Dispose(); }
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(); }
IEnumerator CreateAnswer() { if (_rtcType != RTCTYPE.ANSWER) { yield break; } //アンサー var op4 = localConnection.CreateAnswer(ref AnswerOptions); yield return(op4); var op5 = localConnection.SetLocalDescription(ref op4.desc); yield return(op5); //TextSDP(op4.desc, _mySDPText); SendSDP(op4.desc, NCMBStateData.MyNCMBstate.SENDED_answer); Debug.Log("create answer"); }
private IEnumerator SignalingOffer(RTCPeerConnection @from, RTCPeerConnection to) { var op1 = @from.CreateOffer(); yield return(op1); var desc = op1.Desc; var op2 = @from.SetLocalDescription(ref desc); yield return(op2); var op3 = to.SetRemoteDescription(ref desc); yield return(op3); var op4 = to.CreateAnswer(); yield return(op4); desc = op4.Desc; var op5 = to.SetLocalDescription(ref desc); yield return(op5); var op6 = @from.SetRemoteDescription(ref desc); yield return(op6); var op7 = new WaitUntilWithTimeout( () => @from.IceConnectionState == RTCIceConnectionState.Connected || @from.IceConnectionState == RTCIceConnectionState.Completed, 5000); yield return(op7); Assert.That(op7.IsCompleted, Is.True); var op8 = new WaitUntilWithTimeout( () => to.IceConnectionState == RTCIceConnectionState.Connected || to.IceConnectionState == RTCIceConnectionState.Completed, 5000); yield return(op8); Assert.That(op8.IsCompleted, Is.True); }
private static IEnumerator NegotiationPeer(RTCPeerConnection localPeer, RTCPeerConnection remotePeer) { var opCreateOffer = localPeer.CreateOffer(); yield return(opCreateOffer); if (opCreateOffer.IsError) { OnCreateSessionDescriptionError(opCreateOffer.Error); yield break; } var offerDesc = opCreateOffer.Desc; yield return(localPeer.SetLocalDescription(ref offerDesc)); Debug.Log($"Offer from LocalPeer \n {offerDesc.sdp}"); yield return(remotePeer.SetRemoteDescription(ref offerDesc)); var opCreateAnswer = remotePeer.CreateAnswer(); yield return(opCreateAnswer); if (opCreateAnswer.IsError) { OnCreateSessionDescriptionError(opCreateAnswer.Error); yield break; } var answerDesc = opCreateAnswer.Desc; yield return(remotePeer.SetLocalDescription(ref answerDesc)); Debug.Log($"Answer from RemotePeer \n {answerDesc.sdp}"); yield return(localPeer.SetRemoteDescription(ref answerDesc)); }
public void MessageFromPeerTaskRun(int peerId, string content) { PeerId = peerId; Task.Run(async() => { Debug.Assert(_peerId == PeerId || _peerId == -1); Debug.Assert(content.Length > 0); if (_peerId != PeerId && _peerId != -1) { Debug.WriteLine("Received a message from unknown peer " + "while already in a conversation with a different peer."); return; } if (!JsonObject.TryParse(content, out JsonObject jMessage)) { Debug.WriteLine($"Received unknown message: {content}"); return; } string type = jMessage.ContainsKey(NegotiationAtributes.Type) ? jMessage.GetNamedString(NegotiationAtributes.Type) : null; if (PeerConnection == null) { if (!string.IsNullOrEmpty(type)) { // Create the peer connection only when call is // about to get initiated. Otherwise ignore the // message from peers which could be result // of old (but not yet fully closed) connections. if (type == "offer" || type == "answer" || type == "json") { Debug.Assert(_peerId == -1); _peerId = PeerId; if (!CreatePeerConnection()) { Debug.WriteLine("Failed to initialize our PeerConnection instance"); OnSignedOut.Invoke(this, null); return; } else if (_peerId != PeerId) { Debug.WriteLine("Received a message from unknown peer while already " + "in a conversation with a different peer."); return; } } } else { Debug.WriteLine("[Warn] Received an untyped message after closing peer connection."); return; } } if (PeerConnection != null && !string.IsNullOrEmpty(type)) { if (type == "offer-loopback") { // Loopback not supported Debug.Assert(false); } string sdp = null; sdp = jMessage.ContainsKey(NegotiationAtributes.Sdp) ? jMessage.GetNamedString(NegotiationAtributes.Sdp) : null; if (string.IsNullOrEmpty(sdp)) { Debug.WriteLine("[Error] Can't parse received session description message."); return; } Debug.WriteLine($"Received session description:\n{content}"); RTCSdpType messageType = RTCSdpType.Offer; switch (type) { case "offer": messageType = RTCSdpType.Offer; break; case "answer": messageType = RTCSdpType.Answer; break; case "pranswer": messageType = RTCSdpType.Pranswer; break; default: Debug.Assert(false, type); break; } var sdpInit = new RTCSessionDescriptionInit(); sdpInit.Sdp = sdp; sdpInit.Type = messageType; var description = new RTCSessionDescription(sdpInit); await PeerConnection.SetRemoteDescription(description); if (messageType == RTCSdpType.Offer) { var answerOptions = new RTCAnswerOptions(); IRTCSessionDescription answer = await PeerConnection.CreateAnswer(answerOptions); await PeerConnection.SetLocalDescription(answer); string jsonString = SdpToJsonString(answer); // Send answer OnSendMessageToRemotePeer.Invoke(this, jsonString); } } else { RTCIceCandidate candidate = null; string sdpMid = jMessage.ContainsKey(NegotiationAtributes.SdpMid) ? jMessage.GetNamedString(NegotiationAtributes.SdpMid) : null; double sdpMLineIndex = jMessage.ContainsKey(NegotiationAtributes.SdpMLineIndex) ? jMessage.GetNamedNumber(NegotiationAtributes.SdpMLineIndex) : -1; string sdpCandidate = jMessage.ContainsKey(NegotiationAtributes.Candidate) ? jMessage.GetNamedString(NegotiationAtributes.Candidate) : null; if (string.IsNullOrEmpty(sdpMid) || sdpMLineIndex == -1 || string.IsNullOrEmpty(sdpCandidate)) { Debug.WriteLine($"[Error] Can't parse received message.\n{content}"); return; } var candidateInit = new RTCIceCandidateInit(); candidateInit.Candidate = sdpCandidate; candidateInit.SdpMid = sdpMid; candidateInit.SdpMLineIndex = (ushort)sdpMLineIndex; candidate = new RTCIceCandidate(candidateInit); await PeerConnection.AddIceCandidate(candidate); Debug.WriteLine($"Receiving ice candidate:\n{content}"); } }).Wait(); }
public IEnumerator Signaling() { offerPc.OnIceCandidate = candidate => answerPc.AddIceCandidate(candidate); answerPc.OnIceCandidate = candidate => offerPc.AddIceCandidate(candidate); var pc1CreateOffer = offerPc.CreateOffer(); yield return(pc1CreateOffer); Assert.That(pc1CreateOffer.IsError, Is.False, () => $"Failed {nameof(pc1CreateOffer)}, error:{pc1CreateOffer.Error.message}"); var offerDesc = pc1CreateOffer.Desc; var pc1SetLocalDescription = offerPc.SetLocalDescription(ref offerDesc); yield return(pc1SetLocalDescription); Assert.That(pc1SetLocalDescription.IsError, Is.False, () => $"Failed {nameof(pc1SetLocalDescription)}, error:{pc1SetLocalDescription.Error.message}"); var pc2SetRemoteDescription = answerPc.SetRemoteDescription(ref offerDesc); yield return(pc2SetRemoteDescription); Assert.That(pc2SetRemoteDescription.IsError, Is.False, () => $"Failed {nameof(pc2SetRemoteDescription)}, error:{pc2SetRemoteDescription.Error.message}"); var pc2CreateAnswer = answerPc.CreateAnswer(); yield return(pc2CreateAnswer); Assert.That(pc2CreateAnswer.IsError, Is.False, () => $"Failed {nameof(pc2CreateAnswer)}, error:{pc2CreateAnswer.Error.message}"); var answerDesc = pc2CreateAnswer.Desc; var pc2SetLocalDescription = answerPc.SetLocalDescription(ref answerDesc); yield return(pc2SetLocalDescription); Assert.That(pc2SetLocalDescription.IsError, Is.False, () => $"Failed {nameof(pc2SetLocalDescription)}, error:{pc2SetLocalDescription.Error.message}"); var pc1SetRemoteDescription = offerPc.SetRemoteDescription(ref answerDesc); yield return(pc1SetRemoteDescription); Assert.That(pc1SetRemoteDescription.IsError, Is.False, () => $"Failed {nameof(pc1SetRemoteDescription)}, error:{pc1SetRemoteDescription.Error.message}"); var waitConnectOfferPc = new WaitUntilWithTimeout(() => offerPc.IceConnectionState == RTCIceConnectionState.Connected || offerPc.IceConnectionState == RTCIceConnectionState.Completed, 5000); yield return(waitConnectOfferPc); Assert.That(waitConnectOfferPc.IsCompleted, Is.True); var waitConnectAnswerPc = new WaitUntilWithTimeout(() => answerPc.IceConnectionState == RTCIceConnectionState.Connected || answerPc.IceConnectionState == RTCIceConnectionState.Completed, 5000); yield return(waitConnectAnswerPc); Assert.That(waitConnectAnswerPc.IsCompleted, Is.True); var checkSenders = new WaitUntilWithTimeout(() => offerPc.GetSenders().Any(), 5000); yield return(checkSenders); Assert.That(checkSenders.IsCompleted, Is.True); var checkReceivers = new WaitUntilWithTimeout(() => answerPc.GetReceivers().Any(), 5000); yield return(checkReceivers); Assert.That(checkReceivers.IsCompleted, Is.True); }
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(); }
void OnOffer(ISignaling signaling, DescData e) { RTCSessionDescription _desc; _desc.type = RTCSdpType.Offer; _desc.sdp = e.sdp; var connectionId = e.connectionId; if (m_mapConnectionIdAndPeer.ContainsKey(connectionId)) { return; } var pc = new RTCPeerConnection(); m_mapConnectionIdAndPeer.Add(e.connectionId, pc); pc.OnDataChannel = new DelegateOnDataChannel(channel => { OnDataChannel(pc, channel); }); pc.SetConfiguration(ref m_conf); pc.OnIceCandidate = new DelegateOnIceCandidate(candidate => { signaling.SendCandidate(e.connectionId, candidate); }); pc.OnIceConnectionChange = new DelegateOnIceConnectionChange(state => { if (state == RTCIceConnectionState.Disconnected) { pc.Close(); m_mapConnectionIdAndPeer.Remove(e.connectionId); } }); pc.SetRemoteDescription(ref _desc); foreach (var track in m_listVideoStreamTrack.Concat(m_audioStream.GetTracks())) { RTCRtpSender sender = pc.AddTrack(track); if (!m_mapTrackAndSenderList.TryGetValue(track, out List <RTCRtpSender> list)) { list = new List <RTCRtpSender>(); m_mapTrackAndSenderList.Add(track, list); } list.Add(sender); } RTCAnswerOptions options = default; var op = pc.CreateAnswer(ref options); while (op.MoveNext()) { } if (op.IsError) { Debug.LogError($"Network Error: {op.Error}"); return; } var desc = op.Desc; var opLocalDesc = pc.SetLocalDescription(ref desc); while (opLocalDesc.MoveNext()) { } if (opLocalDesc.IsError) { Debug.LogError($"Network Error: {opLocalDesc.Error}"); return; } signaling.SendAnswer(connectionId, desc); }
void OnOffer(ISignaling signaling, DescData e) { RTCSessionDescription _desc; _desc.type = RTCSdpType.Offer; _desc.sdp = e.sdp; var connectionId = e.connectionId; if (m_mapConnectionIdAndPeer.ContainsKey(connectionId)) { return; } var pc = new RTCPeerConnection(); m_mapConnectionIdAndPeer.Add(e.connectionId, pc); pc.OnDataChannel = new DelegateOnDataChannel(channel => { OnDataChannel(pc, channel); }); pc.SetConfiguration(ref m_conf); pc.OnIceCandidate = new DelegateOnIceCandidate(candidate => { signaling.SendCandidate(e.connectionId, candidate); }); pc.OnIceConnectionChange = new DelegateOnIceConnectionChange(state => { if (state == RTCIceConnectionState.Disconnected) { pc.Close(); m_mapConnectionIdAndPeer.Remove(e.connectionId); } }); //make video bit rate starts at 16000kbits, and 160000kbits at max. string pattern = @"(a=fmtp:\d+ .*level-asymmetry-allowed=.*)\r\n"; _desc.sdp = Regex.Replace(_desc.sdp, pattern, "$1;x-google-start-bitrate=16000;x-google-max-bitrate=160000\r\n"); pc.SetRemoteDescription(ref _desc); foreach (var track in m_listVideoStreamTrack) { pc.AddTrack(track); } foreach (var track in m_audioStream.GetTracks()) { pc.AddTrack(track); } RTCAnswerOptions options = default; var op = pc.CreateAnswer(ref options); while (op.MoveNext()) { } if (op.IsError) { Debug.LogError($"Network Error: {op.Error}"); return; } var desc = op.Desc; var opLocalDesc = pc.SetLocalDescription(ref desc); while (opLocalDesc.MoveNext()) { } if (opLocalDesc.IsError) { Debug.LogError($"Network Error: {opLocalDesc.Error}"); return; } signaling.SendAnswer(connectionId, desc); }
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(); }
IEnumerator CreateDescription(RTCSdpType type) { Debug.Log($"[Create {type}]"); var op = type == RTCSdpType.Offer ? localConnection.CreateOffer(ref offerOption) : localConnection.CreateAnswer(ref answerOptions); yield return(op); if (op.IsError) { Debug.LogError(op.Error.message); } else { yield return(SetDescription(op.Desc, Side.Local)); } }
public IEnumerator AddIceCandidate() { 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); var peer1ReceiveCandidateQueue = new Queue <RTCIceCandidate>(); var peer2ReceiveCandidateQueue = new Queue <RTCIceCandidate>(); peer1.OnIceCandidate = candidate => { peer2ReceiveCandidateQueue.Enqueue(candidate); }; peer2.OnIceCandidate = candidate => { peer1ReceiveCandidateQueue.Enqueue(candidate); }; var obj = new GameObject("audio"); var source = obj.AddComponent <AudioSource>(); source.clip = AudioClip.Create("test", 480, 2, 48000, false); var track = new AudioStreamTrack(source); peer1.AddTrack(track); var op1 = peer1.CreateOffer(); yield return(op1); var desc = op1.Desc; var op2 = peer1.SetLocalDescription(ref desc); yield return(op2); yield return(new WaitUntil(() => peer2ReceiveCandidateQueue.Any())); Assert.That(peer2.AddIceCandidate(peer2ReceiveCandidateQueue.Peek()), Is.False); var op3 = peer2.SetRemoteDescription(ref desc); yield return(op3); Assert.That(peer2.AddIceCandidate(peer2ReceiveCandidateQueue.Dequeue()), Is.True); var op4 = peer2.CreateAnswer(); yield return(op4); desc = op4.Desc; var op5 = peer2.SetLocalDescription(ref desc); yield return(op5); yield return(new WaitUntil(() => peer1ReceiveCandidateQueue.Any())); Assert.That(peer1.AddIceCandidate(peer1ReceiveCandidateQueue.Peek()), Is.False); var op6 = peer1.SetRemoteDescription(ref desc); yield return(op6); Assert.That(peer1.AddIceCandidate(peer1ReceiveCandidateQueue.Dequeue()), Is.True); var op7 = new WaitUntilWithTimeout( () => peer1.IceConnectionState == RTCIceConnectionState.Connected || peer1.IceConnectionState == RTCIceConnectionState.Completed, 5000); yield return(op7); Assert.That(op7.IsCompleted, Is.True); var op8 = new WaitUntilWithTimeout( () => peer2.IceConnectionState == RTCIceConnectionState.Connected || peer2.IceConnectionState == RTCIceConnectionState.Completed, 5000); yield return(op8); Assert.That(op8.IsCompleted, Is.True); foreach (var candidate in peer1ReceiveCandidateQueue) { Assert.That(peer1.AddIceCandidate(candidate), Is.True); } peer1ReceiveCandidateQueue.Clear(); foreach (var candidate in peer2ReceiveCandidateQueue) { Assert.That(peer2.AddIceCandidate(candidate), Is.True); } peer2ReceiveCandidateQueue.Clear(); track.Dispose(); peer1.Close(); peer2.Close(); Object.DestroyImmediate(source.clip); Object.DestroyImmediate(obj); }
public IEnumerator PeerConnectionStateChange() { 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); RTCPeerConnectionState state1 = default; RTCPeerConnectionState state2 = default; RTCIceConnectionState iceState1 = default; RTCIceConnectionState iceState2 = default; peer1.OnIceCandidate = candidate => { peer2.AddIceCandidate(candidate); }; peer2.OnIceCandidate = candidate => { peer1.AddIceCandidate(candidate); }; peer1.OnConnectionStateChange = state => { state1 = state; }; peer2.OnConnectionStateChange = state => { state2 = state; }; peer1.OnIceConnectionChange = state => { iceState1 = state; }; peer2.OnIceConnectionChange = state => { iceState2 = state; }; Assert.That(state1, Is.EqualTo(RTCPeerConnectionState.New)); Assert.That(state2, Is.EqualTo(RTCPeerConnectionState.New)); var obj = new GameObject("audio"); var source = obj.AddComponent <AudioSource>(); source.clip = AudioClip.Create("test", 480, 2, 48000, false); AudioStreamTrack track1 = new AudioStreamTrack(source); peer1.AddTrack(track1); var op1 = peer1.CreateOffer(); 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(); 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(() => state1 == RTCPeerConnectionState.Connected && state2 == RTCPeerConnectionState.Connected, 5000); yield return(op7); Assert.That(op7.IsCompleted, Is.True); var op8 = new WaitUntilWithTimeout(() => (iceState1 == RTCIceConnectionState.Connected || iceState1 == RTCIceConnectionState.Completed) && (iceState2 == RTCIceConnectionState.Connected || iceState2 == RTCIceConnectionState.Completed) , 5000); yield return(op8); Assert.That(op8.IsCompleted, Is.True); peer1.Close(); var op9 = new WaitUntilWithTimeout(() => state1 == RTCPeerConnectionState.Closed && iceState2 == RTCIceConnectionState.Disconnected, 5000); yield return(op9); Assert.That(op9.IsCompleted, Is.True); track1.Dispose(); peer2.Close(); Object.DestroyImmediate(source.clip); Object.DestroyImmediate(obj); }
/// <summary> /// Handler for Signaller's OnMessageFromPeer event. /// </summary> /// <param name="peerId">ID of the peer.</param> /// <param name="message">Message from the peer.</param> private void Signaller_OnMessageFromPeer(int peerId, string message) { Task.Run(async() => { Debug.Assert(_peerId == peerId || _peerId == -1); Debug.Assert(message.Length > 0); if (_peerId != peerId && _peerId != -1) { Debug.WriteLine("[Error] Conductor: Received a message from unknown peer while already in a conversation with a different peer."); return; } JsonObject jMessage; if (!JsonObject.TryParse(message, out jMessage)) { Debug.WriteLine("[Error] Conductor: Received unknown message." + message); return; } string type = jMessage.ContainsKey(kSessionDescriptionTypeName) ? jMessage.GetNamedString(kSessionDescriptionTypeName) : null; #if ORTCLIB bool created = false; #endif if (_peerConnection == null) { if (!IsNullOrEmpty(type)) { // Create the peer connection only when call is // about to get initiated. Otherwise ignore the // messages from peers which could be a result // of old (but not yet fully closed) connections. if (type == "offer" || type == "answer" || type == "json") { Debug.Assert(_peerId == -1); _peerId = peerId; IEnumerable <Peer> enumerablePeer = Peers.Where(x => x.Id == peerId); Peer = enumerablePeer.First(); #if ORTCLIB created = true; _signalingMode = Helper.SignalingModeForClientName(Peer.Name); #endif _connectToPeerCancelationTokenSource = new CancellationTokenSource(); _connectToPeerTask = CreatePeerConnection(_connectToPeerCancelationTokenSource.Token); bool connectResult = await _connectToPeerTask; _connectToPeerTask = null; _connectToPeerCancelationTokenSource.Dispose(); if (!connectResult) { Debug.WriteLine("[Error] Conductor: Failed to initialize our PeerConnection instance"); await Signaller.SignOut(); return; } else if (_peerId != peerId) { Debug.WriteLine("[Error] Conductor: Received a message from unknown peer while already in a conversation with a different peer."); return; } } } else { Debug.WriteLine("[Warn] Conductor: Received an untyped message after closing peer connection."); return; } } if (_peerConnection != null && !IsNullOrEmpty(type)) { if (type == "offer-loopback") { // Loopback not supported Debug.Assert(false); } string sdp = null; #if ORTCLIB if (jMessage.ContainsKey(kSessionDescriptionJsonName)) { var containerObject = new JsonObject { { kSessionDescriptionJsonName, jMessage.GetNamedObject(kSessionDescriptionJsonName) } }; sdp = containerObject.Stringify(); } else if (jMessage.ContainsKey(kSessionDescriptionSdpName)) { sdp = jMessage.GetNamedString(kSessionDescriptionSdpName); } #else sdp = jMessage.ContainsKey(kSessionDescriptionSdpName) ? jMessage.GetNamedString(kSessionDescriptionSdpName) : null; #endif if (IsNullOrEmpty(sdp)) { Debug.WriteLine("[Error] Conductor: Can't parse received session description message."); return; } #if ORTCLIB RTCSessionDescriptionSignalingType messageType = RTCSessionDescriptionSignalingType.SdpOffer; switch (type) { case "json": messageType = RTCSessionDescriptionSignalingType.Json; break; case "offer": messageType = RTCSessionDescriptionSignalingType.SdpOffer; break; case "answer": messageType = RTCSessionDescriptionSignalingType.SdpAnswer; break; case "pranswer": messageType = RTCSessionDescriptionSignalingType.SdpPranswer; break; default: Debug.Assert(false, type); break; } #else RTCSdpType messageType = RTCSdpType.Offer; switch (type) { case "offer": messageType = RTCSdpType.Offer; break; case "answer": messageType = RTCSdpType.Answer; break; case "pranswer": messageType = RTCSdpType.Pranswer; break; default: Debug.Assert(false, type); break; } #endif Debug.WriteLine("Conductor: Received session description: " + message); await _peerConnection.SetRemoteDescription(new RTCSessionDescription(messageType, sdp)); #if ORTCLIB if ((messageType == RTCSessionDescriptionSignalingType.SdpOffer) || ((created) && (messageType == RTCSessionDescriptionSignalingType.Json))) #else if (messageType == RTCSdpType.Offer) #endif { var answer = await _peerConnection.CreateAnswer(); await _peerConnection.SetLocalDescription(answer); // Send answer SendSdp(answer); #if ORTCLIB OrtcStatsManager.Instance.StartCallWatch(SessionId, false); #endif } } else { RTCIceCandidate candidate = null; #if ORTCLIB if (RTCPeerConnectionSignalingMode.Json != _signalingMode) #endif { var sdpMid = jMessage.ContainsKey(kCandidateSdpMidName) ? jMessage.GetNamedString(kCandidateSdpMidName) : null; var sdpMlineIndex = jMessage.ContainsKey(kCandidateSdpMlineIndexName) ? jMessage.GetNamedNumber(kCandidateSdpMlineIndexName) : -1; var sdp = jMessage.ContainsKey(kCandidateSdpName) ? jMessage.GetNamedString(kCandidateSdpName) : null; //TODO: Check is this proper condition ((String.IsNullOrEmpty(sdpMid) && (sdpMlineIndex == -1)) || String.IsNullOrEmpty(sdp)) if (IsNullOrEmpty(sdpMid) || sdpMlineIndex == -1 || IsNullOrEmpty(sdp)) { Debug.WriteLine("[Error] Conductor: Can't parse received message.\n" + message); return; } #if ORTCLIB candidate = IsNullOrEmpty(sdpMid) ? RTCIceCandidate.FromSdpStringWithMLineIndex(sdp, (ushort)sdpMlineIndex) : RTCIceCandidate.FromSdpStringWithMid(sdp, sdpMid); #else candidate = new RTCIceCandidate(sdp, sdpMid, (ushort)sdpMlineIndex); #endif } #if ORTCLIB else { candidate = RTCIceCandidate.FromJsonString(message); } _peerConnection?.AddIceCandidate(candidate); #else await _peerConnection.AddIceCandidate(candidate); #endif Debug.WriteLine("Conductor: Received candidate : " + message); } }).Wait(); }
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(); }