public async Task Initialization(string user) { try { var config = new PeerConnectionConfiguration { IceServers = new List <IceServer> { new IceServer { Urls = { "stun:stun.l.google.com:19302" } } } }; await Connection.InitializeAsync(config); microphoneSource = await DeviceAudioTrackSource.CreateAsync(); var audioTrackConfig = new LocalAudioTrackInitConfig { trackName = "microphone_track" }; localAudioTrack = LocalAudioTrack.CreateFromSource(microphoneSource, audioTrackConfig); audioTransceiver = Connection.AddTransceiver(MediaKind.Audio); audioTransceiver.LocalAudioTrack = localAudioTrack; audioTransceiver.DesiredDirection = Transceiver.Direction.SendReceive; Console.WriteLine("Peer connection initialized."); } catch (Exception e) { await Log.WriteAsync(e.Message); Console.WriteLine(e); throw; } }
/// <summary> /// Initialize the underlying WebRTC peer connection. /// </summary> /// <remarks> /// This method is asynchronous and completes its task when the initializing completed. /// On successful completion, it also trigger the <see cref="OnInitialized"/> event. /// Note however that this completion is free-threaded and complete immediately when the /// underlying peer connection is initialized, whereas any <see cref="OnInitialized"/> /// event handler is invoked when control returns to the main Unity app thread. The former /// is faster, but does not allow accessing the underlying peer connection because it /// returns before <see cref="OnPostInitialize"/> executed. Therefore it is generally /// recommended to listen to the <see cref="OnInitialized"/> event, and ignore the returned /// <see xref="System.Threading.Tasks.Task"/> object. /// </remarks> private async Task <WebRTC.PeerConnection> InitializePluginAsync(CancellationToken token) { // Ensure Android binding is initialized before accessing the native implementation Android.Initialize(); #if UNITY_WSA && !UNITY_EDITOR if (Library.UsedAudioDeviceModule == AudioDeviceModule.LegacyModule) { // Preventing access to audio crashes the ADM1 at startup and the entire application. bool permissionGranted = await UwpUtils.RequestAccessAsync(StreamingCaptureMode.Audio); if (!permissionGranted) { return(null); } } #endif // Create the peer connection managed wrapper and its native implementation var nativePeer = new WebRTC.PeerConnection(); nativePeer.AudioTrackAdded += (RemoteAudioTrack track) => { // Tracks will be output by AudioReceivers, so avoid outputting them twice. track.OutputToDevice(false); }; Debug.Log("Initializing WebRTC Peer Connection..."); var config = new PeerConnectionConfiguration(); foreach (var server in IceServers) { config.IceServers.Add(new IceServer { Urls = { server.ToString() }, TurnUserName = IceUsername, TurnPassword = IceCredential }); } try { await nativePeer.InitializeAsync(config, token); return(nativePeer); } catch (OperationCanceledException canceled) { throw canceled; } catch (Exception ex) { nativePeer.Dispose(); token.ThrowIfCancellationRequested(); EnsureIsMainAppThread(); var errorMessage = new StringBuilder(); errorMessage.Append("WebRTC plugin initializing failed. See full log for exception details.\n"); errorMessage.Append($"Exception: {ex.Message}"); OnError.Invoke(errorMessage.ToString()); throw ex; } }
public async void PeerConnectionDefault() { using (var pc = new PeerConnection()) { var config = new PeerConnectionConfiguration(); await pc.InitializeAsync(config); } }
public async Task SctpError() { // Setup var config = new PeerConnectionConfiguration(); var pc1 = new PeerConnection(); var pc2 = new PeerConnection(); await pc1.InitializeAsync(config); await pc2.InitializeAsync(config); pc1.LocalSdpReadytoSend += async(string type, string sdp) => { await pc2.SetRemoteDescriptionAsync(type, sdp); if (type == "offer") { pc2.CreateAnswer(); } }; pc2.LocalSdpReadytoSend += async(string type, string sdp) => { await pc1.SetRemoteDescriptionAsync(type, sdp); if (type == "offer") { pc1.CreateAnswer(); } }; pc1.IceCandidateReadytoSend += (string candidate, int sdpMlineindex, string sdpMid) => pc2.AddIceCandidate(sdpMid, sdpMlineindex, candidate); pc2.IceCandidateReadytoSend += (string candidate, int sdpMlineindex, string sdpMid) => pc1.AddIceCandidate(sdpMid, sdpMlineindex, candidate); // Connect { var c1 = new ManualResetEventSlim(false); var c2 = new ManualResetEventSlim(false); pc1.Connected += () => c1.Set(); pc2.Connected += () => c2.Set(); Assert.True(pc1.CreateOffer()); Assert.True(c1.Wait(TimeSpan.FromSeconds(60.0))); Assert.True(c2.Wait(TimeSpan.FromSeconds(60.0))); Assert.True(pc1.IsConnected); Assert.True(pc1.IsConnected); } // Try to add a data channel. This should fail because SCTP was not negotiated. Assert.ThrowsAsync <SctpNotNegotiatedException>(async() => await pc1.AddDataChannelAsync("dummy", false, false)); Assert.ThrowsAsync <SctpNotNegotiatedException>(async() => await pc1.AddDataChannelAsync(42, "dummy", false, false)); // Clean-up pc1.Close(); pc1.Dispose(); pc2.Close(); pc2.Dispose(); }
/// <summary> /// Initialize the peer connection. /// </summary> /// <returns>A task that completes once the peer connection is ready to be used.</returns> public async Task InitializePeerConnectionAsync() { Logger.Log("Initializing the peer connection..."); // Cannot run in UI thread on UWP because this will initialize the global factory // (first library call) which needs to be done on a background thread. await ThreadHelper.RunOnWorkerThread(() => Library.ShutdownOptions = Library.ShutdownOptionsFlags.LogLiveObjects); // Initialize the native peer connection object try { var config = new PeerConnectionConfiguration { SdpSemantic = _sdpSemantic, IceServers = new List <IceServer> { _iceServer } }; await _peerConnection.InitializeAsync(config); RaisePropertyChanged("IsPeerInitialized"); } catch (Exception ex) { Logger.Log($"WebRTC native plugin init failed: {ex.Message}"); throw ex; } Logger.Log("Peer connection initialized."); OnPeerInitialized(); //using (_sessionViewModel.GetNegotiationDeferral()) { //// As a convenience, add 1 audio and 1 video transceivers //// TODO - make that more flexible //AddPendingTransceiver(MediaKind.Audio, "audio_transceiver_0"); //AddPendingTransceiver(MediaKind.Video, "video_transceiver_1"); // It is CRUCIAL to add any data channel BEFORE the SDP offer is sent, if data channels are // to be used at all. Otherwise the SCTP will not be negotiated, and then all channels will // stay forever in the kConnecting state. // https://stackoverflow.com/questions/43788872/how-are-data-channels-negotiated-between-two-peers-with-webrtc await _peerConnection.AddDataChannelAsync(ChatChannelID, "chat", true, true); } //_videoPlayer.CurrentStateChanged += OnMediaStateChanged; //_videoPlayer.MediaOpened += OnMediaOpened; //_videoPlayer.MediaFailed += OnMediaFailed; //_videoPlayer.MediaEnded += OnMediaEnded; //_videoPlayer.RealTimePlayback = true; //_videoPlayer.AutoPlay = false; // Bind the XAML UI control (videoPlayerElement) to the MediaFoundation rendering pipeline (_videoPlayer) // so that the former can render in the UI the video frames produced in the background by the latter. //videoPlayerElement.SetMediaPlayer(_videoPlayer); }
protected async Task MakeICECall(PeerConnection pc1, PeerConnection pc2) { var evExchangeCompleted = new ManualResetEventSlim(initialState: false); pc1.LocalSdpReadytoSend += async(SdpMessage message) => { await pc2.SetRemoteDescriptionAsync(message); if (message.Type == SdpMessageType.Offer) { pc2.CreateAnswer(); } else { evExchangeCompleted.Set(); } }; pc2.LocalSdpReadytoSend += async(SdpMessage message) => { await pc1.SetRemoteDescriptionAsync(message); if (message.Type == SdpMessageType.Offer) { pc1.CreateAnswer(); } else { evExchangeCompleted.Set(); } }; pc1.IceCandidateReadytoSend += (string candidate, int sdpMlineindex, string sdpMid) => { pc2.AddIceCandidate(sdpMid, sdpMlineindex, candidate); }; pc2.IceCandidateReadytoSend += (string candidate, int sdpMlineindex, string sdpMid) => { pc1.AddIceCandidate(sdpMid, sdpMlineindex, candidate); }; var pcConfig = new PeerConnectionConfiguration(); await pc1.InitializeAsync(pcConfig); await pc2.InitializeAsync(pcConfig); var ev1 = new ManualResetEventSlim(initialState: false); var ev2 = new ManualResetEventSlim(initialState: false); pc1.Connected += () => ev1.Set(); pc2.Connected += () => ev2.Set(); evExchangeCompleted.Reset(); pc1.CreateOffer(); ev1.Wait(millisecondsTimeout: 5000); ev2.Wait(millisecondsTimeout: 5000); evExchangeCompleted.Wait(millisecondsTimeout: 5000); }
static async Task Main() { try { Console.WriteLine("Starting..."); ClientWebSocket ws = new ClientWebSocket(); CancellationTokenSource cts = new CancellationTokenSource(); // Set up the peer connection. var pc = new PeerConnection(); pc.LocalSdpReadytoSend += async(string type, string sdp) => { Console.WriteLine($"Local SDP ready {type}"); //Console.WriteLine(sdp); // Send out SDP offer to the remote peer. await ws.SendAsync(Encoding.UTF8.GetBytes(sdp), WebSocketMessageType.Text, true, cts.Token); }; var config = new PeerConnectionConfiguration(); await pc.InitializeAsync(config); Console.WriteLine("Peer connection initialized."); await pc.AddLocalAudioTrackAsync(); await pc.AddLocalVideoTrackAsync(new PeerConnection.LocalVideoTrackSettings()); await ws.ConnectAsync(new Uri(WEBSOCKET_SERVER_URI), cts.Token); pc.CreateOffer(); // Wait for the SDP answer to arrive from the remote peer. byte[] answerSdpBuffer = new byte[8192]; var recvRes = await ws.ReceiveAsync(answerSdpBuffer, cts.Token); string answerSdp = Encoding.UTF8.GetString(answerSdpBuffer, 0, recvRes.Count); //Console.WriteLine($"answer sdp: {answerSdp}"); pc.SetRemoteDescription("answer", answerSdp); // Don't need the web socket anymore. await ws.CloseAsync(WebSocketCloseStatus.NormalClosure, null, cts.Token); Console.WriteLine("Press any key to exit..."); Console.ReadLine(); } catch (Exception e) { Console.WriteLine(e.Message); } }
private static PeerConnectionConfiguration CreateSetting() { // Here the main settings of PeerConnection object // If you want to someone change in settings of PeerConnection objects // You can make it here PeerConnectionConfiguration setting = new PeerConnectionConfiguration(); setting.IceServers.AddRange(LoadFromConfigAllSTUN()); setting.IceServers.AddRange(LoadFromConfigAllTURN()); //Console.WriteLine("Creating PeerConnection"); return(setting); }
private async Task InitializeWebRTC(HttpContext context, WebSocket webSocket) { Console.WriteLine("Initializing WebRTC"); var config = new PeerConnectionConfiguration { IceServers = new List <IceServer> { new IceServer { Urls = { Config.STUN_URI } } } }; await this.peerConnection.InitializeAsync(config); Console.WriteLine("Peer connection initialized."); var signaler = new WebSocketSignaler(this.peerConnection, webSocket); signaler.SdpMessageReceived += async(SdpMessage message) => { await this.peerConnection.SetRemoteDescriptionAsync(message); if (message.Type == SdpMessageType.Offer) { this.peerConnection.CreateAnswer(); } }; signaler.IceCandidateReceived += (IceCandidate candidate) => { this.peerConnection.AddIceCandidate(candidate); }; this.peerConnection.Connected += () => { Console.WriteLine("!!! --- PeerConnection: connected --- !!!"); }; this.peerConnection.IceStateChanged += (IceConnectionState newState) => { Console.WriteLine($"!!! --- ICE state: {newState} --- !!!"); }; this.peerConnection.RenegotiationNeeded += () => { this.peerConnection.CreateOffer(); }; await signaler.StartAsync(); Console.WriteLine("Signaler started"); Console.Read(); signaler.Stop(); this.peerConnection.Close(); Console.WriteLine("Program terminated."); }
public async Task LocalNoICE() { var pc1 = new PeerConnection(); var pc2 = new PeerConnection(); var evExchangeCompleted = new ManualResetEventSlim(initialState: false); pc1.LocalSdpReadytoSend += async(SdpMessage message) => { await pc2.SetRemoteDescriptionAsync(message); if (message.Type == SdpMessageType.Offer) { pc2.CreateAnswer(); } else { evExchangeCompleted.Set(); } }; pc2.LocalSdpReadytoSend += async(SdpMessage message) => { await pc1.SetRemoteDescriptionAsync(message); if (message.Type == SdpMessageType.Offer) { pc1.CreateAnswer(); } else { evExchangeCompleted.Set(); } }; var pcConfig = new PeerConnectionConfiguration(); await pc1.InitializeAsync(pcConfig); await pc2.InitializeAsync(pcConfig); var ev1 = new ManualResetEventSlim(initialState: false); pc1.Connected += () => ev1.Set(); evExchangeCompleted.Reset(); pc1.CreateOffer(); ev1.Wait(millisecondsTimeout: 5000); evExchangeCompleted.Wait(millisecondsTimeout: 5000); pc1.Close(); pc2.Close(); }
protected async Task MakeICECall(PeerConnection pc1, PeerConnection pc2) { pc1.LocalSdpReadytoSend += (string type, string sdp) => { pc2.SetRemoteDescription(type, sdp); if (type == "offer") { pc2.CreateAnswer(); } }; pc2.LocalSdpReadytoSend += (string type, string sdp) => { pc1.SetRemoteDescription(type, sdp); if (type == "offer") { pc1.CreateAnswer(); } }; pc1.IceCandidateReadytoSend += (string candidate, int sdpMlineindex, string sdpMid) => { pc2.AddIceCandidate(sdpMid, sdpMlineindex, candidate); }; pc2.IceCandidateReadytoSend += (string candidate, int sdpMlineindex, string sdpMid) => { pc1.AddIceCandidate(sdpMid, sdpMlineindex, candidate); }; var pcConfig = new PeerConnectionConfiguration(); await pc1.InitializeAsync(pcConfig); await pc2.InitializeAsync(pcConfig); var ev1 = new ManualResetEventSlim(initialState: false); var ev2 = new ManualResetEventSlim(initialState: false); pc1.Connected += () => ev1.Set(); pc2.Connected += () => ev2.Set(); pc1.CreateOffer(); ev1.Wait(millisecondsTimeout: 5000); ev2.Wait(millisecondsTimeout: 5000); }
public static PeerConnectionConfiguration GetPeerConnectionConfiguration(CommunicationRelayConfiguration relayConfiguration) { IReadOnlyList <CommunicationIceServer> iceServers = (IReadOnlyList <CommunicationIceServer>)relayConfiguration.IceServers; var webRTCIceServers = new List <IceServer>(); foreach (CommunicationIceServer iceServer in iceServers) { var webRTCIceServer = new IceServer(); webRTCIceServer.Urls = (List <string>)iceServer.Urls; webRTCIceServer.TurnUserName = iceServer.Username; webRTCIceServer.TurnPassword = iceServer.Credential; webRTCIceServers.Add(webRTCIceServer); } PeerConnectionConfiguration configuration = new PeerConnectionConfiguration(); configuration.IceServers = webRTCIceServers; return(configuration); }
/// <summary> /// Internal handler to actually initialize the /// </summary> private Task InitializePluginAsync(CancellationToken token) { Debug.Log("Initializing WebRTC plugin..."); var config = new PeerConnectionConfiguration(); foreach (var server in IceServers) { config.IceServers.Add(new IceServer { Urls = { server.ToString() }, TurnUserName = IceUsername, TurnPassword = IceCredential }); } return(_nativePeer.InitializeAsync(config, token).ContinueWith((initTask) => { token.ThrowIfCancellationRequested(); if (initTask.Exception != null) { _mainThreadWorkQueue.Enqueue(() => { var errorMessage = new StringBuilder(); errorMessage.Append("WebRTC plugin initializing failed. See full log for exception details.\n"); Exception ex = initTask.Exception; while (ex is AggregateException ae) { errorMessage.Append($"AggregationException: {ae.Message}\n"); ex = ae.InnerException; } errorMessage.Append($"Exception: {ex.Message} {ex.ToString()}"); OnError.Invoke(errorMessage.ToString()); }); throw initTask.Exception; } _mainThreadWorkQueue.Enqueue(OnPostInitialize); }, token)); }
public async Task LocalNoICE() { var pc1 = new PeerConnection(); var pc2 = new PeerConnection(); pc1.LocalSdpReadytoSend += async(string type, string sdp) => { await pc2.SetRemoteDescriptionAsync(type, sdp); if (type == "offer") { pc2.CreateAnswer(); } }; pc2.LocalSdpReadytoSend += async(string type, string sdp) => { await pc1.SetRemoteDescriptionAsync(type, sdp); if (type == "offer") { pc1.CreateAnswer(); } }; var pcConfig = new PeerConnectionConfiguration(); await pc1.InitializeAsync(pcConfig); await pc2.InitializeAsync(pcConfig); var ev1 = new ManualResetEventSlim(initialState: false); pc1.Connected += () => ev1.Set(); pc1.CreateOffer(); ev1.Wait(millisecondsTimeout: 5000); pc1.Close(); pc2.Close(); }
public void SetupConnection() { // Create the 2 peers var config = new PeerConnectionConfiguration(); pc1_ = new PeerConnection(); pc2_ = new PeerConnection(); pc1_.InitializeAsync(config).Wait(); // cannot use async/await in OneTimeSetUp pc2_.InitializeAsync(config).Wait(); // Allocate callback events connectedEvent1_ = new ManualResetEventSlim(false); connectedEvent2_ = new ManualResetEventSlim(false); iceConnectedEvent1_ = new ManualResetEventSlim(false); iceConnectedEvent2_ = new ManualResetEventSlim(false); renegotiationEvent1_ = new ManualResetEventSlim(false); renegotiationEvent2_ = new ManualResetEventSlim(false); trackAddedEvent1_ = new ManualResetEventSlim(false); trackAddedEvent2_ = new ManualResetEventSlim(false); trackRemovedEvent1_ = new ManualResetEventSlim(false); trackRemovedEvent2_ = new ManualResetEventSlim(false); // Connect all signals pc1_.Connected += OnConnected1; pc2_.Connected += OnConnected2; pc1_.LocalSdpReadytoSend += OnLocalSdpReady1; pc2_.LocalSdpReadytoSend += OnLocalSdpReady2; pc1_.IceCandidateReadytoSend += OnIceCandidateReadytoSend1; pc2_.IceCandidateReadytoSend += OnIceCandidateReadytoSend2; pc1_.IceStateChanged += OnIceStateChanged1; pc2_.IceStateChanged += OnIceStateChanged2; pc1_.RenegotiationNeeded += OnRenegotiationNeeded1; pc2_.RenegotiationNeeded += OnRenegotiationNeeded2; pc1_.TrackAdded += OnTrackAdded1; pc2_.TrackAdded += OnTrackAdded2; pc1_.TrackRemoved += OnTrackRemoved1; pc2_.TrackRemoved += OnTrackRemoved2; }
public async Task Init(IceServerModel[] iceServers) { Logger.Debug("Starting WebRTC connection."); IceServers = iceServers; PeerSession = new PeerConnection(); var iceList = IceServers.Select(x => new IceServer() { Urls = { x.Url }, TurnPassword = x.TurnPassword ?? string.Empty, TurnUserName = x.TurnUsername ?? string.Empty }).ToList(); var config = new PeerConnectionConfiguration() { IceServers = iceList }; await PeerSession.InitializeAsync(config); PeerSession.LocalSdpReadytoSend += PeerSession_LocalSdpReadytoSend;; PeerSession.Connected += PeerConnection_Connected; PeerSession.IceStateChanged += PeerConnection_IceStateChanged; PeerSession.IceCandidateReadytoSend += PeerSession_IceCandidateReadytoSend;; CaptureChannel = await PeerSession.AddDataChannelAsync("ScreenCapture", true, true); CaptureChannel.BufferingChanged += DataChannel_BufferingChanged; CaptureChannel.MessageReceived += CaptureChannel_MessageReceived; CaptureChannel.StateChanged += CaptureChannel_StateChanged; VideoSource = ExternalVideoTrackSource.CreateFromArgb32Callback(GetCaptureFrame); Transceiver = PeerSession.AddTransceiver(MediaKind.Video); PeerSession.CreateOffer(); }
private async void OnLoaded(object sender, RoutedEventArgs e) { // Request access to microphone and camera var settings = new MediaCaptureInitializationSettings(); settings.StreamingCaptureMode = StreamingCaptureMode.AudioAndVideo; var capture = new MediaCapture(); await capture.InitializeAsync(settings); // Retrieve a list of available video capture devices (webcams). List <VideoCaptureDevice> deviceList = await PeerConnection.GetVideoCaptureDevicesAsync(); // Get the device list and, for example, print them to the debugger console foreach (var device in deviceList) { // This message will show up in the Output window of Visual Studio Debugger.Log(0, "", $"Webcam {device.name} (id: {device.id})\n"); } _peerConnection = new PeerConnection(); var config = new PeerConnectionConfiguration { IceServers = new List <IceServer> { new IceServer { Urls = { "stun:stun.l.google.com:19302" } } } }; await _peerConnection.InitializeAsync(config); Debugger.Log(0, "", "Peer connection initialized successfully.\n"); await _peerConnection.AddLocalAudioTrackAsync(); if (Settings.m_showLocal) { //LocalVideoTrack _localVideoTrack; await _peerConnection.AddLocalVideoTrackAsync(); _peerConnection.I420LocalVideoFrameReady += Peer_LocalI420AFrameReady; await _peerConnection.AddLocalAudioTrackAsync(); remoteVideoPlayerElement.Visibility = Visibility.Visible; } else { _peerConnection.Connected += () => { Debugger.Log(0, "", "PeerConnection: connected.\n"); }; _peerConnection.IceStateChanged += (IceConnectionState newState) => { Debugger.Log(0, "", $"ICE state: {newState}\n"); }; _peerConnection.I420RemoteVideoFrameReady += Peer_RemoteI420AFrameReady; _peerConnection.LocalSdpReadytoSend += Peer_LocalSdpReadytoSend; _peerConnection.IceCandidateReadytoSend += Peer_IceCandidateReadytoSend; // Initialize the signaler _signaler = new NodeDssSignaler() { HttpServerAddress = "http://10.44.160.22:3000/", LocalPeerId = "DINF-D60015-43A", RemotePeerId = "HOLOLENS-RO2J0", }; _signaler.OnMessage += (NodeDssSignaler.Message msg) => { switch (msg.MessageType) { case NodeDssSignaler.Message.WireMessageType.Offer: _peerConnection.SetRemoteDescription("offer", msg.Data); _peerConnection.CreateAnswer(); break; case NodeDssSignaler.Message.WireMessageType.Answer: _peerConnection.SetRemoteDescription("answer", msg.Data); break; case NodeDssSignaler.Message.WireMessageType.Ice: var parts = msg.Data.Split(new string[] { msg.IceDataSeparator }, StringSplitOptions.RemoveEmptyEntries); // Note the inverted arguments for historical reasons. // 'candidate' is last in AddIceCandidate(), but first in the message. string sdpMid = parts[2]; int sdpMlineindex = int.Parse(parts[1]); string candidate = parts[0]; _peerConnection.AddIceCandidate(sdpMid, sdpMlineindex, candidate); break; } }; _signaler.StartPollingAsync(); } // Interactions Debug.WriteLine("[Playback::start] Waiting for a connection..."); m_dsUdpSocket = new DatagramSocket(); m_dsUdpSocket.MessageReceived += Socket_MessageReceived; // Initialization UDP communication try { await m_dsUdpSocket.ConnectAsync(new EndpointPair(new HostName(Settings.m_sIPLocalUDP), Settings.m_sPortLocalUDP, new HostName(Settings.m_sIPRemoteUDP), Settings.m_sPortRemoteUDP)); m_output = new DataWriter(m_dsUdpSocket.OutputStream); Debug.WriteLine("[Playback::start] UDP connection initialization ok"); } catch (Exception) { Debug.WriteLine("[Playback::start] Error - UDP connection initialization "); } }
static async Task Main() { try { Console.WriteLine("Starting..."); //create and Initialize capture object to record audio var waveFormat = new WaveFormat(44100, 32, 2, AudioEncoding.MpegLayer3); WasapiCapture capture = new WasapiCapture(true, AudioClientShareMode.Shared, 100, waveFormat); //initialize the selected device for recording capture.Initialize(); //fill ice servers here List <string> urls = new List <string>(); using var pc = new PeerConnection(); var config = new PeerConnectionConfiguration { IceServers = new List <IceServer> { new IceServer { Urls = urls, } } , BundlePolicy = BundlePolicy.MaxBundle }; await pc.InitializeAsync(config); Console.WriteLine("Peer connection initialized."); //create audio transceiver Transceiver transceiver = pc.AddTransceiver(MediaKind.Audio); transceiver.DesiredDirection = Transceiver.Direction.ReceiveOnly; Console.WriteLine("Create audio transceiver ..."); DataChannel chanel = await pc.AddDataChannelAsync("Data", true, true, cancellationToken : default); string url = ""; WebSocketSharp.WebSocket signaling = new WebSocket(url); signaling.SslConfiguration.EnabledSslProtocols = System.Security.Authentication.SslProtocols.Tls12; signaling.OnMessage += async(sender, message) => { try { //response messages may differ from service provider to another, adjust WebsocketResponse object accordingly var messageObject = JsonConvert.DeserializeObject <WebsocketResponse>(message.Data); var mess = new SdpMessage { Content = messageObject.Data.Sdp, Type = SdpMessage.StringToType("answer") }; if (!string.IsNullOrEmpty(mess.Content)) { Console.WriteLine("Sdpmessage: {0}, Type: {1}", mess.Content, mess.Type); await pc.SetRemoteDescriptionAsync(mess); if (mess.Type == SdpMessageType.Answer) { bool res = pc.CreateAnswer(); Console.WriteLine("Answer created? {0}", res); } } } catch (Exception e) { Console.WriteLine(e.Message); } }; signaling.OnError += (sender, e) => { Console.WriteLine(e.Message, e.Exception); }; signaling.OnOpen += (sender, e) => { pc.CreateOffer(); Console.WriteLine("open"); }; signaling.Connect(); transceiver.Associated += (tranciever) => { Console.WriteLine("Transivier: {0}, {1}", tranciever.Name, tranciever.StreamIDs); }; pc.LocalSdpReadytoSend += (SdpMessage message) => { Console.WriteLine(message.Content); //modify the offer message according to your need var data = new { streamId = "", sdp = message.Content }; var payload = JsonConvert.SerializeObject(new { type = "cmd", transId = 0, name = "view", data = data }); Console.WriteLine("Sdp offer to send: " + payload); signaling.Send(payload); }; pc.RenegotiationNeeded += () => { Console.WriteLine("Regotiation needed"); }; //when a remote audio track is added, start recording pc.AudioTrackAdded += (RemoteAudioTrack track) => { //create a wavewriter to write the data to WaveWriter w = new WaveWriter("audio.mp3", capture.WaveFormat); //setup an eventhandler to receive the recorded data capture.DataAvailable += (s, e) => { //save the recorded audio w.Write(e.Data, e.Offset, e.ByteCount); }; //start recording capture.Start(); //this should output the sound track.OutputToDevice(true); //track.AudioFrameReady += (AudioFrame frame) => //{ //you can print anything here if you want to make sure that's you're recieving audio //}; }; pc.Connected += () => { Console.WriteLine("Connected"); Console.WriteLine(pc.DataChannels.Count); }; pc.IceStateChanged += (IceConnectionState newState) => { Console.WriteLine($"ICE state: {newState}"); }; Console.WriteLine("Press enter to stop"); Console.ReadLine(); //stop recording capture.Stop(); pc.Close(); signaling.Close(); Console.WriteLine("Program termined."); } catch (Exception e) { Console.WriteLine(e.Message); } }
/// <summary> /// Initialize the peer connection. /// </summary> /// <returns>A task that completes once the peer connection is ready to be used.</returns> public async Task InitializePeerConnectionAsync() { Logger.Log("Initializing the peer connection..."); // Cannot run in UI thread on UWP because this will initialize the global factory // (first library call) which needs to be done on a background thread. await ThreadHelper.RunOnWorkerThread(() => Library.ShutdownOptions = Library.ShutdownOptionsFlags.LogLiveObjects); // Initialize the native peer connection object try { var config = new PeerConnectionConfiguration { SdpSemantic = _sdpSemantic, IceServers = new List <IceServer> { _iceServer } }; await _peerConnection.InitializeAsync(config); RaisePropertyChanged("IsPeerInitialized"); } catch (Exception ex) { Logger.Log($"WebRTC native plugin init failed: {ex.Message}"); throw ex; } Logger.Log("Peer connection initialized."); OnPeerInitialized(); // It is CRUCIAL to add any data channel BEFORE the SDP offer is sent, if data channels are // to be used at all. Otherwise the SCTP will not be negotiated, and then all channels will // stay forever in the kConnecting state. // https://stackoverflow.com/questions/43788872/how-are-data-channels-negotiated-between-two-peers-with-webrtc await _peerConnection.AddDataChannelAsync(ChatChannelID, "chat", true, true); //_videoPlayer.CurrentStateChanged += OnMediaStateChanged; //_videoPlayer.MediaOpened += OnMediaOpened; //_videoPlayer.MediaFailed += OnMediaFailed; //_videoPlayer.MediaEnded += OnMediaEnded; //_videoPlayer.RealTimePlayback = true; //_videoPlayer.AutoPlay = false; // Bind the XAML UI control (videoPlayerElement) to the MediaFoundation rendering pipeline (_videoPlayer) // so that the former can render in the UI the video frames produced in the background by the latter. //videoPlayerElement.SetMediaPlayer(_videoPlayer); //// Uncomment to initialize local transceivers and tracks. //if (Utils.IsFirstInstance()) //{ // // Add transceivers // var transceiverA = AddTransceiver(MediaKind.Audio, // new TransceiverInitSettings { Name = "audio_transceiver" }); // var transceiverV = AddTransceiver(MediaKind.Video, // new TransceiverInitSettings { Name = "video_transceiver", }); // // Add audio track // var sourceA = await DeviceAudioTrackSource.CreateAsync(new LocalAudioDeviceInitConfig()); // var trackA = LocalAudioTrack.CreateFromSource(sourceA, // new LocalAudioTrackInitConfig { trackName = "local_audio" }); // AddAudioTrack(trackA, "Audio Device"); // // Add the track to the transceiver. // { // var transceiverVM = Transceivers.First(t => t.Transceiver == transceiverA); // var trackVM = transceiverVM.AvailableSenders.Last(); // transceiverVM.Sender = trackVM; // } // // Add video track // var sourceV = await DeviceVideoTrackSource.CreateAsync( // new LocalVideoDeviceInitConfig // { // videoDevice = new VideoCaptureDevice // { // id = @"<insert_device_id>" // }, // videoProfileId = string.Empty, // width = 640, // height = 480, // framerate = 30 // }); // // Crate the track // var trackV = LocalVideoTrack.CreateFromSource(sourceV, // new LocalVideoTrackInitConfig { trackName = "local_video" }); // AddVideoTrack(trackV, "Video Device"); // // Add the track to the transceiver. // { // var transceiverVM = Transceivers.First(t => t.Transceiver == transceiverV); // var trackVM = transceiverVM.AvailableSenders.Last(); // transceiverVM.Sender = trackVM; // } //} }
public async Task InBand() { // Setup var config = new PeerConnectionConfiguration(); var pc1 = new PeerConnection(); var pc2 = new PeerConnection(); await pc1.InitializeAsync(config); await pc2.InitializeAsync(config); pc1.LocalSdpReadytoSend += (string type, string sdp) => { pc2.SetRemoteDescription(type, sdp); if (type == "offer") { pc2.CreateAnswer(); } }; pc2.LocalSdpReadytoSend += (string type, string sdp) => { pc1.SetRemoteDescription(type, sdp); if (type == "offer") { pc1.CreateAnswer(); } }; pc1.IceCandidateReadytoSend += (string candidate, int sdpMlineindex, string sdpMid) => pc2.AddIceCandidate(sdpMid, sdpMlineindex, candidate); pc2.IceCandidateReadytoSend += (string candidate, int sdpMlineindex, string sdpMid) => pc1.AddIceCandidate(sdpMid, sdpMlineindex, candidate); // Add dummy out-of-band data channel to force SCTP negotiating. // Otherwise after connecting AddDataChannelAsync() will fail. await pc1.AddDataChannelAsync(42, "dummy", false, false); await pc2.AddDataChannelAsync(42, "dummy", false, false); // Connect { var c1 = new ManualResetEventSlim(false); var c2 = new ManualResetEventSlim(false); pc1.Connected += () => c1.Set(); pc2.Connected += () => c2.Set(); Assert.True(pc1.CreateOffer()); Assert.True(c1.Wait(TimeSpan.FromSeconds(60.0))); Assert.True(c2.Wait(TimeSpan.FromSeconds(60.0))); Assert.True(pc1.IsConnected); Assert.True(pc1.IsConnected); } // Negotiate data channel in-band DataChannel data1 = null; DataChannel data2 = null; { var c2 = new ManualResetEventSlim(false); pc2.DataChannelAdded += (DataChannel channel) => { data2 = channel; c2.Set(); }; data1 = await pc1.AddDataChannelAsync("test_data_channel", true, true); Assert.IsNotNull(data1); Assert.True(c2.Wait(TimeSpan.FromSeconds(60.0))); Assert.IsNotNull(data2); Assert.AreEqual(data1.Label, data2.Label); // Do not test DataChannel.ID; at this point for in-band channels the ID has not // been agreed upon with the remote peer yet. } // Send data { var c2 = new ManualResetEventSlim(false); string sentText = "Some sample text"; byte[] msg = Encoding.UTF8.GetBytes(sentText); data2.MessageReceived += (byte[] _msg) => { var receivedText = Encoding.UTF8.GetString(_msg); Assert.AreEqual(sentText, receivedText); c2.Set(); }; data1.SendMessage(msg); Assert.True(c2.Wait(TimeSpan.FromSeconds(60.0))); } // Clean-up pc1.Close(); pc1.Dispose(); pc2.Close(); pc2.Dispose(); }
static async Task Main(string[] args) { Transceiver audioTransceiver = null; Transceiver videoTransceiver = null; AudioTrackSource audioTrackSource = null; VideoTrackSource videoTrackSource = null; LocalAudioTrack localAudioTrack = null; LocalVideoTrack localVideoTrack = null; try { bool needVideo = Array.Exists(args, arg => (arg == "-v") || (arg == "--video")); bool needAudio = Array.Exists(args, arg => (arg == "-a") || (arg == "--audio")); // Asynchronously retrieve a list of available video capture devices (webcams). var deviceList = await PeerConnection.GetVideoCaptureDevicesAsync(); // For example, print them to the standard output foreach (var device in deviceList) { Console.WriteLine($"Found webcam {device.name} (id: {device.id})"); } // Create a new peer connection automatically disposed at the end of the program using var pc = new PeerConnection(); // Initialize the connection with a STUN server to allow remote access var config = new PeerConnectionConfiguration { IceServers = new List <IceServer> { new IceServer { Urls = { "stun:stun.l.google.com:19302" } } } }; await pc.InitializeAsync(config); Console.WriteLine("Peer connection initialized."); // Record video from local webcam, and send to remote peer if (needVideo) { Console.WriteLine("Opening local webcam..."); videoTrackSource = await DeviceVideoTrackSource.CreateAsync(); Console.WriteLine("Create local video track..."); var trackSettings = new LocalVideoTrackInitConfig { trackName = "webcam_track" }; localVideoTrack = LocalVideoTrack.CreateFromSource(videoTrackSource, trackSettings); Console.WriteLine("Create video transceiver and add webcam track..."); videoTransceiver = pc.AddTransceiver(MediaKind.Video); videoTransceiver.DesiredDirection = Transceiver.Direction.SendReceive; videoTransceiver.LocalVideoTrack = localVideoTrack; } // Record audio from local microphone, and send to remote peer if (needAudio) { Console.WriteLine("Opening local microphone..."); audioTrackSource = await DeviceAudioTrackSource.CreateAsync(); Console.WriteLine("Create local audio track..."); var trackSettings = new LocalAudioTrackInitConfig { trackName = "mic_track" }; localAudioTrack = LocalAudioTrack.CreateFromSource(audioTrackSource, trackSettings); Console.WriteLine("Create audio transceiver and add mic track..."); audioTransceiver = pc.AddTransceiver(MediaKind.Audio); audioTransceiver.DesiredDirection = Transceiver.Direction.SendReceive; audioTransceiver.LocalAudioTrack = localAudioTrack; } // Setup signaling Console.WriteLine("Starting signaling..."); var signaler = new NamedPipeSignaler.NamedPipeSignaler(pc, "testpipe"); signaler.SdpMessageReceived += async(SdpMessage message) => { await pc.SetRemoteDescriptionAsync(message); if (message.Type == SdpMessageType.Offer) { pc.CreateAnswer(); } }; signaler.IceCandidateReceived += (IceCandidate candidate) => { pc.AddIceCandidate(candidate); }; await signaler.StartAsync(); // Start peer connection pc.Connected += () => { Console.WriteLine("PeerConnection: connected."); }; pc.IceStateChanged += (IceConnectionState newState) => { Console.WriteLine($"ICE state: {newState}"); }; int numFrames = 0; pc.VideoTrackAdded += (RemoteVideoTrack track) => { track.I420AVideoFrameReady += (I420AVideoFrame frame) => { ++numFrames; if (numFrames % 60 == 0) { Console.WriteLine($"Received video frames: {numFrames}"); } }; }; if (signaler.IsClient) { Console.WriteLine("Connecting to remote peer..."); pc.CreateOffer(); } else { Console.WriteLine("Waiting for offer from remote peer..."); } Console.WriteLine("Press a key to stop recording..."); Console.ReadKey(true); signaler.Stop(); } catch (Exception e) { Console.WriteLine(e.Message); } localAudioTrack?.Dispose(); localVideoTrack?.Dispose(); Console.WriteLine("Program termined."); localAudioTrack.Dispose(); localVideoTrack.Dispose(); audioTrackSource.Dispose(); videoTrackSource.Dispose(); }
static async Task Main(string[] args) { DataChannel dataChannel = null; try { // Create a new peer connection automatically disposed at the end of the program using var pc = new PeerConnection(); // Initialize the connection with a STUN server to allow remote access var config = new PeerConnectionConfiguration { IceServers = new List <IceServer> { new IceServer { Urls = { "stun:stun.l.google.com:19302" } } } }; await pc.InitializeAsync(config); Console.WriteLine("Peer connection initialized."); Console.WriteLine("Opening data channel"); dataChannel = await pc.AddDataChannelAsync("data", true, true); // Setup signaling Console.WriteLine("Starting signaling..."); var signaler = new NamedPipeSignaler.NamedPipeSignaler(pc, "testpipe"); signaler.SdpMessageReceived += (string type, string sdp) => { pc.SetRemoteDescription(type, sdp); if (type == "offer") { pc.CreateAnswer(); } }; signaler.IceCandidateReceived += (string sdpMid, int sdpMlineindex, string candidate) => { pc.AddIceCandidate(sdpMid, sdpMlineindex, candidate); }; await signaler.StartAsync(); // Start peer connection pc.Connected += () => { Console.WriteLine("PeerConnection: connected."); }; pc.IceStateChanged += (IceConnectionState newState) => { Console.WriteLine($"ICE state: {newState}"); }; pc.DataChannelAdded += (DataChannel c) => { Console.WriteLine("DataChannel added"); c.MessageReceived += (byte[] _msg) => { Console.WriteLine("received {0} bytes", _msg.Length); }; }; if (signaler.IsClient) { Console.WriteLine("Connecting to remote peer..."); pc.CreateOffer(); } else { Console.WriteLine("Waiting for offer from remote peer..."); } Console.WriteLine("Press a 'S' to send data. 'Esc' to exit ..."); ConsoleKeyInfo key; while ((key = Console.ReadKey(true)).Key != ConsoleKey.Escape) { if (key.Key == ConsoleKey.S) { Console.WriteLine("Sending data"); dataChannel.SendMessage(new byte[3000]); } } signaler.Stop(); } catch (Exception e) { Console.WriteLine(e.Message); } Console.WriteLine("Program termined."); }
private async void Window_Initialized(object sender, EventArgs e) { _peerConnection = new PeerConnection(); var config = new PeerConnectionConfiguration { IceServers = new List <IceServer> { new IceServer { Urls = { "turn:35.193.0.31:3478" }, TurnPassword = "******", TurnUserName = "******" } } }; _peerConnection.Connected += () => { Debugger.Log(0, "", "Peerconnection: DONE"); }; _peerConnection.IceStateChanged += (IceConnectionState newState) => { Debugger.Log(0, "", $"ICE state: {newState}\n"); }; await _peerConnection.InitializeAsync(config); _dc = await _peerConnection.AddDataChannelAsync(14, "vzgo", true, true); Debugger.Log(0, "", "Peer connection initialized successfully.\n"); _peerConnection.LocalSdpReadytoSend += Peer_LocalSdpReadytoSendAsync; _peerConnection.IceCandidateReadytoSend += Peer_IceCandidateReadytoSend; _hubConnection = new HubConnectionBuilder() .WithUrl(new Uri(SignallerConstants.SignallerUrl)) .AddJsonProtocol() .WithAutomaticReconnect(new[] { TimeSpan.Zero, TimeSpan.Zero, TimeSpan.FromSeconds(10) }) .Build(); _hubConnection.On <string>("Message", (message) => { var msg = JsonConvert.DeserializeObject <SignallingMessage>(message); switch (msg.MessageType) { case SignallingMessage.WireMessageType.Offer: _peerConnection.SetRemoteDescription("offer", msg.Data); _peerConnection.CreateAnswer(); break; case SignallingMessage.WireMessageType.Answer: _peerConnection.SetRemoteDescription("answer", msg.Data); break; case SignallingMessage.WireMessageType.Ice: var parts = msg.Data.Split(new string[] { msg.IceDataSeparator }, StringSplitOptions.RemoveEmptyEntries); // Note the inverted arguments for historical reasons. // 'candidate' is last in AddIceCandidate(), but first in the message. string sdpMid = parts[2]; int sdpMlineindex = int.Parse(parts[1]); string candidate = parts[0]; _peerConnection.AddIceCandidate(sdpMid, sdpMlineindex, candidate); break; } }); await _hubConnection.StartAsync(); await _hubConnection.InvokeAsync("JoinRoom", SignallerConstants.RoomName); }
//Loaded-EventHandler of ui: executes after ui-loading private async void OnLoaded(object sender, RoutedEventArgs e) { //Request access to mic and cam MediaCaptureInitializationSettings settings = new MediaCaptureInitializationSettings(); settings.StreamingCaptureMode = StreamingCaptureMode.AudioAndVideo; MediaCapture capture = new MediaCapture(); await capture.InitializeAsync(settings); //Get list of cams camList = await PeerConnection.GetVideoCaptureDevicesAsync(); //Print list to log foreach (var cam in camList) { Debugger.Log(0, "", $"Webcam: {cam.name} (id: {cam.id})\n"); } //Ask user for ids (show MessageBox) await ShowIdInputBoxAsync(); //New PeerConnection (Access to WebRTC) peerConnection = new PeerConnection(); //Create PeerConnection-config PeerConnectionConfiguration config = new PeerConnectionConfiguration() { IceServers = new List <IceServer>() { //Using google stun server for testing new IceServer() { Urls = { "stun:stun.l.google.com:19302" } } } }; //Initialize PeerContection await peerConnection.InitializeAsync(config); //Event fires, when local video frame is captured and ready for rendering peerConnection.I420LocalVideoFrameReady += Peer_LocalI420FrameReady; //Event fires, when remote video frame is receved and ready for rendering peerConnection.I420RemoteVideoFrameReady += Peer_RemoteI420FrameReady; //Events fires, when SdpMessage is ready for sending peerConnection.LocalSdpReadytoSend += Peer_LocalSdpReadytoSend; //Event fires, when IceCandidate is ready for sending peerConnection.IceCandidateReadytoSend += Peer_IceCandidateReadytoSend; //Set DebuggingLog-messages peerConnection.Connected += () => Debugger.Log(0, "", "PeerConnection: connected\n"); peerConnection.IceStateChanged += (IceConnectionState newState) => Debugger.Log(0, "", $"ICE state: {newState}\n"); Debugger.Log(0, "", "Peer conection initialized successfully\n"); //Adds cam-tracks from standart (first) devices [add parameter to specify cam-device or -specifications] await peerConnection.AddLocalVideoTrackAsync(new PeerConnection.LocalVideoTrackSettings() { videoDevice = cam }); //Same for mic [no specifications possible: always uses the first mic in list] await peerConnection.AddLocalAudioTrackAsync(); //Initialize the signaler (Properties from MessageBox) signaler = new NodeDssSignaler() { HttpServerAddress = nodeDssServerIp, LocalPeerId = localId, RemotePeerId = remoteId }; signaler.OnMessage += (NodeDssSignaler.Message msg) => { switch (msg.MessageType) { case NodeDssSignaler.Message.WireMessageType.Offer: peerConnection.SetRemoteDescription("offer", msg.Data); peerConnection.CreateAnswer(); break; case NodeDssSignaler.Message.WireMessageType.Answer: peerConnection.SetRemoteDescription("answer", msg.Data); break; case NodeDssSignaler.Message.WireMessageType.Ice: string[] parts = msg.Data.Split(new string[] { msg.IceDataSeparator }, StringSplitOptions.RemoveEmptyEntries); //Changing order of parts string sdpMid = parts[2]; int sdpMlineindex = int.Parse(parts[1]); string candidate = parts[0]; peerConnection.AddIceCandidate(sdpMid, sdpMlineindex, candidate); break; } }; signaler.StartPollingAsync(); }
private static async void MessageReceived(WebRtcSession session, string msg) { Console.WriteLine($"web socket recv: {msg.Length} bytes"); JObject jsonMsg = JObject.Parse(msg); if ((string)jsonMsg["type"] == "ice") { Console.WriteLine($"Adding remote ICE candidate {msg}."); while (!session.pc.Initialized) { // This delay is needed due to an initialise bug in the Microsoft.MixedReality.WebRTC // nuget packages up to version 0.2.3. On master awaiting pc.InitializeAsync does end // up with the pc object being ready. Console.WriteLine("Sleeping for 1s while peer connection is initialising..."); await Task.Delay(1000); } session.pc.AddIceCandidate((string)jsonMsg["sdpMLineindex"], (int)jsonMsg["sdpMid"], (string)jsonMsg["candidate"]); } else if ((string)jsonMsg["type"] == "sdp") { Console.WriteLine("Received remote peer SDP offer."); var config = new PeerConnectionConfiguration(); session.pc.IceCandidateReadytoSend += (string candidate, int sdpMlineindex, string sdpMid) => { Console.WriteLine($"Sending ice candidate: {candidate}"); JObject iceCandidate = new JObject { { "type", "ice" }, { "candidate", candidate }, { "sdpMLineindex", sdpMlineindex }, { "sdpMid", sdpMid } }; session.Context.WebSocket.Send(iceCandidate.ToString()); }; session.pc.IceStateChanged += (newState) => { Console.WriteLine($"ice connection state changed to {newState}."); }; session.pc.LocalSdpReadytoSend += (string type, string sdp) => { Console.WriteLine($"SDP answer ready, sending to remote peer."); // Send our SDP answer to the remote peer. JObject sdpAnswer = new JObject { { "type", "sdp" }, { "answer", sdp } }; session.Context.WebSocket.Send(sdpAnswer.ToString()); }; await session.pc.InitializeAsync(config).ContinueWith((t) => { session.pc.SetRemoteDescription("offer", (string)jsonMsg["offer"]); if (!session.pc.CreateAnswer()) { Console.WriteLine("Failed to create peer connection answer, closing peer connection."); session.pc.Close(); session.Context.WebSocket.Close(); } }); // Create a new form to display the video feed from the WebRTC peer. var form = new Form(); form.AutoSize = true; form.BackgroundImageLayout = ImageLayout.Center; PictureBox picBox = null; form.HandleDestroyed += (object sender, EventArgs e) => { Console.WriteLine("Form closed, closing peer connection."); session.pc.Close(); session.Context.WebSocket.Close(); }; session.pc.ARGBRemoteVideoFrameReady += (frame) => { var width = frame.width; var height = frame.height; var stride = frame.stride; var data = frame.data; if (picBox == null) { picBox = new PictureBox { Size = new Size((int)width, (int)height), Location = new Point(0, 0), Visible = true }; form.BeginInvoke(new Action(() => { form.Controls.Add(picBox); })); } form.BeginInvoke(new Action(() => { System.Drawing.Bitmap bmpImage = new System.Drawing.Bitmap((int)width, (int)height, (int)stride, System.Drawing.Imaging.PixelFormat.Format32bppArgb, data); picBox.Image = bmpImage; })); }; Application.EnableVisualStyles(); Application.Run(form); } }
public void SetupConnection() { Assert.AreEqual(0, Library.ReportLiveObjects()); // Create the 2 peers var config = new PeerConnectionConfiguration(); config.SdpSemantic = sdpSemantic_; pc1_ = new PeerConnection(); pc2_ = new PeerConnection(); pc1_.InitializeAsync(config).Wait(); // cannot use async/await in OneTimeSetUp pc2_.InitializeAsync(config).Wait(); exchangePending_ = false; exchangeCompleted_ = new ManualResetEventSlim(false); // Allocate callback events connectedEvent1_ = new ManualResetEventSlim(false); connectedEvent2_ = new ManualResetEventSlim(false); remoteDescAppliedEvent1_ = new ManualResetEventSlim(false); remoteDescAppliedEvent2_ = new ManualResetEventSlim(false); iceConnectedEvent1_ = new ManualResetEventSlim(false); iceConnectedEvent2_ = new ManualResetEventSlim(false); renegotiationEvent1_ = new ManualResetEventSlim(false); renegotiationEvent2_ = new ManualResetEventSlim(false); dataChannelAddedEvent1_ = new ManualResetEventSlim(false); dataChannelAddedEvent2_ = new ManualResetEventSlim(false); dataChannelRemovedEvent1_ = new ManualResetEventSlim(false); dataChannelRemovedEvent2_ = new ManualResetEventSlim(false); audioTrackAddedEvent1_ = new ManualResetEventSlim(false); audioTrackAddedEvent2_ = new ManualResetEventSlim(false); audioTrackRemovedEvent1_ = new ManualResetEventSlim(false); audioTrackRemovedEvent2_ = new ManualResetEventSlim(false); videoTrackAddedEvent1_ = new ManualResetEventSlim(false); videoTrackAddedEvent2_ = new ManualResetEventSlim(false); videoTrackRemovedEvent1_ = new ManualResetEventSlim(false); videoTrackRemovedEvent2_ = new ManualResetEventSlim(false); // Connect all signals pc1_.Connected += OnConnected1; pc2_.Connected += OnConnected2; pc1_.LocalSdpReadytoSend += OnLocalSdpReady1; pc2_.LocalSdpReadytoSend += OnLocalSdpReady2; pc1_.IceCandidateReadytoSend += OnIceCandidateReadytoSend1; pc2_.IceCandidateReadytoSend += OnIceCandidateReadytoSend2; pc1_.IceStateChanged += OnIceStateChanged1; pc2_.IceStateChanged += OnIceStateChanged2; pc1_.RenegotiationNeeded += OnRenegotiationNeeded1; pc2_.RenegotiationNeeded += OnRenegotiationNeeded2; pc1_.DataChannelAdded += OnDataChannelAdded1; pc2_.DataChannelAdded += OnDataChannelAdded2; pc1_.DataChannelRemoved += OnDataChannelRemoved1; pc2_.DataChannelRemoved += OnDataChannelRemoved2; pc1_.AudioTrackAdded += OnAudioTrackAdded1; pc2_.AudioTrackAdded += OnAudioTrackAdded2; pc1_.AudioTrackRemoved += OnAudioTrackRemoved1; pc2_.AudioTrackRemoved += OnAudioTrackRemoved2; pc1_.VideoTrackAdded += OnVideoTrackAdded1; pc2_.VideoTrackAdded += OnVideoTrackAdded2; pc1_.VideoTrackRemoved += OnVideoTrackRemoved1; pc2_.VideoTrackRemoved += OnVideoTrackRemoved2; // Enable automatic renegotiation suspendOffer1_ = false; suspendOffer2_ = false; }
static async Task Main(string[] args) { try { bool needVideo = Array.Exists(args, arg => (arg == "-v") || (arg == "--video")); bool needAudio = Array.Exists(args, arg => (arg == "-a") || (arg == "--audio")); // Asynchronously retrieve a list of available video capture devices (webcams). var deviceList = await PeerConnection.GetVideoCaptureDevicesAsync(); // For example, print them to the standard output foreach (var device in deviceList) { Console.WriteLine($"Found webcam {device.name} (id: {device.id})"); } // Create a new peer connection automatically disposed at the end of the program using var pc = new PeerConnection(); // Initialize the connection with a STUN server to allow remote access var config = new PeerConnectionConfiguration { IceServers = new List <IceServer> { new IceServer { Urls = { "stun:stun.l.google.com:19302" } } } }; await pc.InitializeAsync(config); Console.WriteLine("Peer connection initialized."); // Record video from local webcam, and send to remote peer if (needVideo) { Console.WriteLine("Opening local webcam..."); await pc.AddLocalVideoTrackAsync(); } // Record audio from local microphone, and send to remote peer if (needAudio) { Console.WriteLine("Opening local microphone..."); await pc.AddLocalAudioTrackAsync(); } // Setup signaling Console.WriteLine("Starting signaling..."); var signaler = new NamedPipeSignaler.NamedPipeSignaler(pc, "testpipe"); signaler.SdpMessageReceived += (string type, string sdp) => { pc.SetRemoteDescription(type, sdp); if (type == "offer") { pc.CreateAnswer(); } }; signaler.IceCandidateReceived += (string sdpMid, int sdpMlineindex, string candidate) => { pc.AddIceCandidate(sdpMid, sdpMlineindex, candidate); }; await signaler.StartAsync(); // Start peer connection pc.Connected += () => { Console.WriteLine("PeerConnection: connected."); }; pc.IceStateChanged += (IceConnectionState newState) => { Console.WriteLine($"ICE state: {newState}"); }; int numFrames = 0; pc.I420RemoteVideoFrameReady += (I420AVideoFrame frame) => { ++numFrames; if (numFrames % 60 == 0) { Console.WriteLine($"Received video frames: {numFrames}"); } }; if (signaler.IsClient) { Console.WriteLine("Connecting to remote peer..."); pc.CreateOffer(); } else { Console.WriteLine("Waiting for offer from remote peer..."); } Console.WriteLine("Press a key to stop recording..."); Console.ReadKey(true); signaler.Stop(); } catch (Exception e) { Console.WriteLine(e.Message); } Console.WriteLine("Program termined."); }
private static async void MessageReceived(WebSocketContext context, string msg) { Console.WriteLine($"websocket recv: {msg}"); // Set up the peer connection. var pc = new PeerConnection(); var config = new PeerConnectionConfiguration(); await pc.InitializeAsync(config); // Create a new form to display the video feed from the WebRTC peer. var form = new Form(); form.AutoSize = true; form.BackgroundImageLayout = ImageLayout.Center; PictureBox picBox = null; pc.SetRemoteDescription("offer", msg); pc.LocalSdpReadytoSend += (string type, string sdp) => { Console.WriteLine($"Local SDP ready {type}"); // Send our SDP answer to the remote peer. context.WebSocket.Send(sdp); }; if (pc.CreateAnswer()) { Console.WriteLine("Peer connection answer successfully created."); } else { Console.WriteLine("Failed to create peer connection answer."); pc.Close(); } pc.ARGBRemoteVideoFrameReady += (frame) => { var width = frame.width; var height = frame.height; var stride = frame.stride; var data = frame.data; if (picBox == null) { picBox = new PictureBox { Size = new Size((int)width, (int)height), Location = new Point(0, 0), Visible = true }; form.BeginInvoke(new Action(() => { form.Controls.Add(picBox); })); } form.BeginInvoke(new Action(() => { System.Drawing.Bitmap bmpImage = new System.Drawing.Bitmap((int)width, (int)height, (int)stride, System.Drawing.Imaging.PixelFormat.Format32bppArgb, data); picBox.Image = bmpImage; })); }; Application.EnableVisualStyles(); Application.Run(form); }
public static extern uint PeerConnection_Create(PeerConnectionConfiguration config, IntPtr peer, out PeerConnectionHandle peerHandleOut);
public async Task <string> InitiateCallRTC() { var list = new List <string>(); list.Add(this.Configuration.GetSection("Key")["iceServer"]); AudioTrackSource microphoneSource = null; LocalAudioTrack localAudioTrack = null; Transceiver audioTransceiver = null; var iceServer = new IceServer { Urls = list, TurnPassword = this.Configuration.GetSection("Key")["turnPwd"], TurnUserName = this.Configuration.GetSection("Key")["turnUser"] }; var serverList = new List <IceServer>(); serverList.Add(iceServer); var connectionConfig = new PeerConnectionConfiguration { IceServers = serverList, IceTransportType = IceTransportType.All, BundlePolicy = BundlePolicy.Balanced, SdpSemantic = SdpSemantic.UnifiedPlan }; var connection = new PeerConnection(); await connection.InitializeAsync(connectionConfig); microphoneSource = await DeviceAudioTrackSource.CreateAsync(); var audioTrackConfig = new LocalAudioTrackInitConfig { trackName = "microphone_track" }; localAudioTrack = LocalAudioTrack.CreateFromSource(microphoneSource, audioTrackConfig); audioTransceiver = connection.AddTransceiver(MediaKind.Audio); audioTransceiver.LocalAudioTrack = localAudioTrack; audioTransceiver.DesiredDirection = Transceiver.Direction.SendReceive; var signaler = new NamedPipeSignaler.NamedPipeSignaler(connection, "testpipe"); connection.Connected += () => { Console.WriteLine("PeerConnection: connected."); }; signaler.SdpMessageReceived += async(SdpMessage message) => { // Note: we use 'await' to ensure the remote description is applied // before calling CreateAnswer(). Failing to do so will prevent the // answer from being generated, and the connection from establishing. await connection.SetRemoteDescriptionAsync(message); if (message.Type == SdpMessageType.Offer) { connection.CreateAnswer(); } }; await signaler.StartAsync(); signaler.IceCandidateReceived += (IceCandidate candidate) => { connection.AddIceCandidate(candidate); }; connection.IceStateChanged += (IceConnectionState newState) => { Console.WriteLine($"ICE state: {newState}"); }; if (signaler.IsClient) { Console.WriteLine("Connecting to remote peer..."); connection.CreateOffer(); } else { Console.WriteLine("Waiting for offer from remote peer..."); } return(connection.IsConnected + "-" + connection.Name + "-"); }