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); }
/// <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); }