예제 #1
0
        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);
        }
예제 #2
0
        /// <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);
            }
        }
예제 #3
0
    /// <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));
            }
        }
    }
예제 #4
0
        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);
        }
예제 #5
0
        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();
        }
예제 #6
0
        private RTCSessionDescriptionAsyncOperation StartClientOffer()
        {
            // Client caller code.
            RTCOfferOptions options = default;

            return(_peerConnection.CreateOffer(ref options));
        }
예제 #7
0
        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);
            }
        }
예제 #8
0
        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();
        }
예제 #9
0
        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);
        }
예제 #10
0
        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();
        }
예제 #11
0
        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);
        }
예제 #12
0
        /// <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();
            }
        }
예제 #13
0
        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);
        }
예제 #14
0
        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();
        }
예제 #16
0
        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);
        }
예제 #17
0
        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);
        }
예제 #18
0
        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();
        }
예제 #19
0
        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();
        }
예제 #22
0
        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);
        }
예제 #23
0
        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));
        }
예제 #24
0
        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();
        }
예제 #25
0
        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();
        }
예제 #26
0
        /// <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();
                }
            }
        }
예제 #27
0
    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();
    }
예제 #28
0
        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;
        }
예제 #29
0
        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();
        }
예제 #30
0
        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();
        }