public override async Task OnSdpAnswerAsync(RelayMessage message) { await Context.PeerConnection.SetRemoteDescription(new RTCSessionDescription(RTCSdpType.Answer, message.Payload)); if (SdpUtils.IsHold(message.Payload)) { await Context.SwitchState(new Held()); } else { await Context.SwitchState(new Active()); } }
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 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); }
public override async Task OnSdpOfferAsync(RelayMessage message) { bool isHold = SdpUtils.IsHold(message.Payload); if (isHold) { Context.VoipHelper.SetCallHeld(); } else { Context.VoipHelper.SetCallActive(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); } if (isHold) { // 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); } Context.LocalStream?.Stop(); Context.LocalStream = null; Context.RemoteStream?.Stop(); Context.RemoteStream = null; Context.ResetRenderers(); } MediaVideoTrack oldVideoTrack = Context.RemoteStream?.GetVideoTracks()?.FirstOrDefault(); await Context.PeerConnection.SetRemoteDescription(new RTCSessionDescription(RTCSdpType.Offer, message.Payload)); MediaVideoTrack newVideoTrack = Context.RemoteStream?.GetVideoTracks()?.FirstOrDefault(); bool videoTrackChanged = oldVideoTrack != null && newVideoTrack != null && oldVideoTrack.Id.CompareTo(newVideoTrack.Id) != 0; if (videoTrackChanged) { Context.ResetRemoteRenderer(); var source = RtcManager.Instance.Media.CreateMediaSource(newVideoTrack, CallContext.PeerMediaStreamId); Context.RemoteVideoRenderer.SetupRenderer(Context.ForegroundProcessId, source, Context.RemoteVideoControlSize); } else if (!isHold) { 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); } } var sdpAnswer = await Context.PeerConnection.CreateAnswer(); await Context.PeerConnection.SetLocalDescription(sdpAnswer); var sdpVideoCodecIds = SdpUtils.GetVideoCodecIds(message.Payload); if (sdpVideoCodecIds.Count > 0) { Context.VideoCodecUsed = Array.Find((await Hub.Instance.MediaSettingsChannel.GetVideoCodecsAsync())?.Codecs, it => it.Id == sdpVideoCodecIds.First())?.FromDto(); } Context.SendToPeer(RelayMessageTags.SdpAnswer, sdpAnswer.Sdp); if (isHold) { await Context.SwitchState(new Held()); } else { await Context.SwitchState(new Active()); } }