public override async Task OnEnteringState()
        {
            Debug.Assert(Context.PeerConnection == null);

            Context.VoipCoordinator.StartOutgoingCall(_callRequest);

            var config = new RTCConfiguration
            {
                IceServers = WebRtcSettingsUtils.ToRTCIceServer(IceServerSettings.IceServers)
            };

            Context.PeerConnection = new RTCPeerConnection(config);

            Context.LocalStream = await Context.Media.GetUserMedia(new RTCMediaStreamConstraints
            {
                videoEnabled = _callRequest.VideoEnabled,
                audioEnabled = true
            });

            Context.PeerConnection.AddStream(Context.LocalStream);
            var sdpOffer = await Context.PeerConnection.CreateOffer();

            var sdpString = sdpOffer.Sdp;

            SdpUtils.SelectCodecs(ref sdpString, DtoExtensions.FromDto(Context.GetAudioCodec()), DtoExtensions.FromDto(Context.GetVideoCodec()));
            sdpOffer.Sdp = sdpString;
            await Context.PeerConnection.SetLocalDescription(sdpOffer);

            var tracks = Context.LocalStream.GetVideoTracks();

            if (tracks.Count > 0)
            {
#if WIN10
                var source = Context.Media.CreateMediaSource(tracks[0], VoipContext.LocalMediaStreamId);
#else
                var source = Context.Media.CreateMediaStreamSource(tracks[0], 30, VoipContext.LocalMediaStreamId);
#endif
                Context.LocalVideoRenderer.SetupRenderer(Context.ForegroundProcessId, source, Context.LocalVideoControlSize);
            }

            Context.SendToPeer(RelayMessageTags.SdpOffer, sdpOffer.Sdp);
        }
Пример #2
0
        /// <summary>
        /// Calls to connect to the selected peer.
        /// </summary>
        /// <param name="peer">Peer to connect to.</param>
        public async void ConnectToPeer(Peer peer)
        {
            Debug.Assert(peer != null);
            Debug.Assert(_peerId == -1);

            if (_peerConnection != null)
            {
                Debug.WriteLine("[Error] Conductor: We only support connecting to one peer at a time");
                return;
            }
#if ORTCLIB
            _signalingMode = Helper.SignalingModeForClientName(peer.Name);
#endif
            _connectToPeerCancelationTokenSource = new System.Threading.CancellationTokenSource();
            _connectToPeerTask = CreatePeerConnection(_connectToPeerCancelationTokenSource.Token);
            bool connectResult = await _connectToPeerTask;
            _connectToPeerTask = null;
            _connectToPeerCancelationTokenSource.Dispose();

            if (connectResult)
            {
                _peerId = peer.Id;
                var offer = await _peerConnection.CreateOffer();

#if !ORTCLIB
                // Alter sdp to force usage of selected codecs
                string newSdp = offer.Sdp;
                SdpUtils.SetMediaBitrate(ref newSdp, "video", VideoBitrate);
                SdpUtils.SelectCodecs(ref newSdp, AudioCodec, VideoCodec);
                offer.Sdp = newSdp;
#endif
                await _peerConnection.SetLocalDescription(offer);

                Debug.WriteLine("Conductor: Sending offer.");
                SendSdp(offer);
#if ORTCLIB
                OrtcStatsManager.Instance.StartCallWatch(SessionId, true);
#endif
            }
        }
        public override async Task OnEnteringStateAsync()
        {
            if (_reason == Reason.HoldCall)
            {
                Context.VoipHelper.SetCallHeld();
            }
            else if (Context.VoipHelper.HasCall())
            {
                Context.VoipHelper.SetCallActive(Context.PeerId, Context.IsVideoEnabled);
            }
            else
            {
                Context.VoipHelper.StartOutgoingCall(Context.PeerId, Context.IsVideoEnabled);
            }

            // If PeerConnection is not null, then this is an SDP renegotiation.
            if (Context.PeerConnection == null)
            {
                var config = new RTCConfiguration
                {
                    IceServers = WebRtcSettingsUtils.ToRTCIceServer(IceServerSettings.IceServers)
                };
                Context.PeerConnection = new RTCPeerConnection(config);
            }

            switch (_reason)
            {
            case Reason.HoldCall:
            {
                // Even for just a renegotiation, it's easier to just teardown the media capture and start over.
                if (Context.LocalStream != null)
                {
                    Context.PeerConnection.RemoveStream(Context.LocalStream);
                }
                if (Context.RemoteStream != null)
                {
                    Context.PeerConnection.RemoveStream(Context.RemoteStream);
                }
                foreach (var stream in Context.PeerConnection.GetLocalStreams())
                {
                    Debug.WriteLine("Streams remaining.");
                }

                Context.LocalStream?.Stop();
                Context.LocalStream = null;
                Context.RemoteStream?.Stop();
                Context.RemoteStream = null;
                Context.ResetRenderers();
                break;
            }

            case Reason.EstablishCall:
            {
                Context.LocalStream?.Stop();
                Context.LocalStream = null;
                Context.RemoteStream?.Stop();
                Context.RemoteStream = null;
                Context.ResetRenderers();

                Context.LocalStream = await RtcManager.Instance.Media.GetUserMedia(new RTCMediaStreamConstraints
                    {
                        videoEnabled = Context.IsVideoEnabled,
                        audioEnabled = true
                    });

                Context.PeerConnection.AddStream(Context.LocalStream);

                // Setup the rendering of the local capture.
                var tracks = Context.LocalStream.GetVideoTracks();
                if (tracks.Count > 0)
                {
                    var source = RtcManager.Instance.Media.CreateMediaSource(tracks[0], CallContext.LocalMediaStreamId);
                    Context.LocalVideoRenderer.SetupRenderer(Context.ForegroundProcessId, source, Context.LocalVideoControlSize);
                }
                break;
            }

            case Reason.SwitchCamera:
            {
                var videoDevice = await Context.MediaSettingsChannel.GetVideoDeviceAsync();

                // We expect the camera we want to switch to is selected.
                if (videoDevice == null)
                {
                    // This could happen only in an error scenario and would have the
                    // effect of loosing the video.
                    // Since will not be able to continue the video call, just end the call.
                    await Context.SwitchState(new HangingUp());

                    return;
                }
                RtcManager.Instance.Media.SelectVideoDevice(videoDevice.FromDto());

                // Remove old video track.
                var  videoTracks       = Context.LocalStream.GetVideoTracks();
                bool videoTrackEnabled = true;
                if (videoTracks.Count > 0)
                {
                    var oldVideoTrack = videoTracks[0];
                    videoTrackEnabled = oldVideoTrack.Enabled;
                    oldVideoTrack.Stop();
                    Context.LocalStream.RemoveTrack(oldVideoTrack);
                }
                videoTracks.Clear();
                Context.ResetLocalRenderer();

                // Create new stream having a new video track.
                var newStream = await RtcManager.Instance.Media.GetUserMedia(new RTCMediaStreamConstraints
                    {
                        videoEnabled = true,
                        audioEnabled = false
                    });

                // Move the new video track from new stream to old stream.
                var newVideoTrack = newStream.GetVideoTracks().First();
                newVideoTrack.Enabled = videoTrackEnabled;
                Context.LocalStream.AddTrack(newVideoTrack);

                newStream.RemoveTrack(newVideoTrack);
                newStream.Stop();

                var source = RtcManager.Instance.Media.CreateMediaSource(newVideoTrack, CallContext.LocalMediaStreamId);
                Context.LocalVideoRenderer.SetupRenderer(Context.ForegroundProcessId, source, Context.LocalVideoControlSize);
                break;
            }
            }

            var sdpOffer = await Context.PeerConnection.CreateOffer();

            var sdpString = sdpOffer.Sdp;

            Org.WebRtc.CodecInfo videoCodecToUse = null;
            // In case of camera switch, try to use the codec from the call's first SDP negotiation.
            if (_reason == Reason.SwitchCamera && Context.VideoCodecUsed != null)
            {
                videoCodecToUse = Context.VideoCodecUsed;
            }
            else
            {
                videoCodecToUse = (await Hub.Instance.MediaSettingsChannel.GetVideoCodecAsync()).FromDto();
            }

            SdpUtils.SelectCodecs(ref sdpString,
                                  (await Hub.Instance.MediaSettingsChannel.GetAudioCodecAsync()).FromDto(),
                                  videoCodecToUse);

            if (_reason == Reason.EstablishCall)
            {
                Context.VideoCodecUsed = videoCodecToUse;
            }

            sdpOffer.Sdp = sdpString;
            await Context.PeerConnection.SetLocalDescription(sdpOffer);

            Context.SendToPeer(RelayMessageTags.SdpOffer, sdpOffer.Sdp);
        }