コード例 #1
0
        public async void PeerConnectionLocalConnect()
        {
            using (var pc1 = new PeerConnection())
            {
                await pc1.InitializeAsync();

                using (var pc2 = new PeerConnection())
                {
                    await pc2.InitializeAsync();

                    // Prepare SDP event handlers
                    pc1.LocalSdpReadytoSend += async(SdpMessage message) =>
                    {
                        await pc2.SetRemoteDescriptionAsync(message);

                        if (message.Type == SdpMessageType.Offer)
                        {
                            pc2.CreateAnswer();
                        }
                    };
                    pc2.LocalSdpReadytoSend += async(SdpMessage message) =>
                    {
                        await pc1.SetRemoteDescriptionAsync(message);

                        if (message.Type == SdpMessageType.Offer)
                        {
                            pc1.CreateAnswer();
                        }
                    };
                    pc1.IceCandidateReadytoSend += (IceCandidate candidate) => pc2.AddIceCandidate(candidate);
                    pc2.IceCandidateReadytoSend += (IceCandidate candidate) => pc1.AddIceCandidate(candidate);

                    // Connect
                    var conn1 = new ManualResetEventSlim(initialState: false);
                    var conn2 = new ManualResetEventSlim(initialState: false);
                    pc1.Connected += () => conn1.Set();
                    pc2.Connected += () => conn2.Set();
                    pc1.CreateOffer();
                    WaitForSdpExchangeCompleted(conn1, conn2);

                    pc1.Close();
                    pc2.Close();
                }
            }
        }
コード例 #2
0
        public async void PeerConnectionLocalConnect()
        {
            using (var pc1 = new PeerConnection())
            {
                await pc1.InitializeAsync();

                using (var pc2 = new PeerConnection())
                {
                    await pc2.InitializeAsync();

                    // Prepare SDP event handlers
                    var completed = new ManualResetEventSlim(initialState: false);
                    pc1.LocalSdpReadytoSend += async(SdpMessage message) =>
                    {
                        // Send caller offer to callee
                        await pc2.SetRemoteDescriptionAsync(message);

                        Assert.AreEqual(SdpMessageType.Offer, message.Type);
                        pc2.CreateAnswer();
                    };
                    pc2.LocalSdpReadytoSend += async(SdpMessage message) =>
                    {
                        // Send callee answer back to caller
                        await pc1.SetRemoteDescriptionAsync(message);

                        Assert.AreEqual(SdpMessageType.Answer, message.Type);
                        completed.Set();
                    };
                    pc1.IceCandidateReadytoSend += (IceCandidate candidate) => pc2.AddIceCandidate(candidate);
                    pc2.IceCandidateReadytoSend += (IceCandidate candidate) => pc1.AddIceCandidate(candidate);

                    // Connect
                    pc1.CreateOffer();
                    WaitForSdpExchangeCompleted(completed);

                    pc1.Close();
                    pc2.Close();
                }
            }
        }
コード例 #3
0
        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();
        }
コード例 #4
0
        //Suspending-EventHandler of app: executes when app turns into suspending-state
        private void App_Suspending(object sender, SuspendingEventArgs e)
        {
            if (peerConnection != null)
            {
                //Closing of PeerConnection
                peerConnection.Close();
                //Disposing of PeerConnection-Resources
                peerConnection.Dispose();
                peerConnection = null;

                Debugger.Log(0, "", "Peer conection disposed successfully\n");
            }

            //Disposing of MediaPlayers
            Mpe_localVideo.SetMediaPlayer(null);
            Mpe_remoteVideo.SetMediaPlayer(null);

            //Disposing of signaler
            if (signaler != null)
            {
                signaler.StopPollingAsync();
                signaler = null;
            }
        }
コード例 #5
0
        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();
        }
コード例 #6
0
ファイル: Connection.cs プロジェクト: tana/Mondeto
 public void Dispose()
 {
     pc.Close();
     pc.Dispose();
 }
コード例 #7
0
ファイル: Program.cs プロジェクト: Vaveform/remote_stand
        static private async Task StartStend()
        {
            var             autoEvent        = new AutoResetEvent(false);
            bool            video_translator = true;
            bool            file_created     = false;
            FileStream      file             = null;
            Quartus         quartus          = Quartus.GetInstance();
            Microcontroller arduino          = Microcontroller.Create();

            if (video_translator)
            {
                // Asynchronously retrieve a list of available video capture devices (webcams).
                var deviceList = await DeviceVideoTrackSource.GetCaptureDevicesAsync();


                // 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
            var pc = new PeerConnection();
            // Initialize the connection with a STUN server to allow remote access
            var config = SystemConfiguration.PeerConnectionSettings;


            await pc.InitializeAsync(config);

            Console.WriteLine("Peer connection initialized.");
            //var chen = await pc.AddDataChannelAsync("sendDataChannel", true, true, cancellationToken: default);
            Console.WriteLine("Opening local webcam...");


            // pc - PeerConnection object
            Transceiver                videoTransceiver = null;
            VideoTrackSource           videoTrackSource = null;
            LocalVideoTrack            localVideoTrack  = null;
            LocalVideoDeviceInitConfig c = new LocalVideoDeviceInitConfig();

            await VideoDeviceSelection();

            videoTrackSource = await Camera.CreateAsync(SystemConfiguration.VideoDeviceSettings);


            WebSocketSharp.WebSocket signaling = new WebSocketSharp.WebSocket(CreateSignalingServerUrl(), "id_token", "alpine");
            pc.LocalSdpReadytoSend += (SdpMessage message) =>
            {
                //Console.WriteLine(SdpMessage.TypeToString(message.Type));
                Console.WriteLine(message.Content);
                //Console.WriteLine(HttpUtility.JavaScriptStringEncode(message.Content));
                Console.WriteLine("Sdp offer to send: {\"data\":{\"description\":{\"type\":\"" + SdpMessage.TypeToString(message.Type) + "\",\"sdp\":\"" + HttpUtility.JavaScriptStringEncode(message.Content) + "\"}}}");
                signaling.Send(message.ToABJson());
            };

            pc.RenegotiationNeeded += () =>
            {
                Console.WriteLine("Regotiation needed");
                bool OfferCreated = pc.CreateOffer();
                Console.WriteLine("OfferCreated? {0}", OfferCreated);
            };
            pc.DataChannelAdded += (DataChannel channel) =>
            {
                Console.WriteLine("Added data channel ID: {0}, Label: {1}; Reliable: {2}, Ordered: {3}", channel.ID, channel.Label, channel.Reliable, channel.Ordered);

                if (channel.Label == "sendDataChannel")
                {
                    channel.MessageReceived += (byte[] mess) => {
                        try
                        {
                            CTP_packet command = JsonSerializer.Deserialize <CTP_packet>(mess);
                            Console.WriteLine(arduino.SendCTP_Command(command));
                        }
                        catch (Exception e)
                        {
                            Console.WriteLine(e.Message);
                        }
                    };
                }
                else
                {
                    if (file_created == false)
                    {
                        file         = new FileStream(channel.Label, FileMode.Append);
                        file_created = true;
                    }
                    channel.MessageReceived += async(byte[] mess) =>
                    {
                        // Console.WriteLine(System.Text.Encoding.Default.GetString(mess));
                        if (mess.Length == 3 && System.Text.Encoding.Default.GetString(mess) == "EOF")
                        {
                            string file_name = file.Name;
                            file.Close();
                            string t = await quartus.RunQuartusCommandAsync($"quartus_pgm -m jtag –o \"p;{file_name}@1\"");

                            File.Delete(file_name);
                            file_created = false;
                        }
                        else
                        {
                            WriteFileSegment(mess, file);
                        }
                    };
                }

                channel.StateChanged += () =>
                {
                    Console.WriteLine("State change: {0}", channel.State);
                };
            };

            pc.IceCandidateReadytoSend += (IceCandidate candidate) =>
            {
                //Console.WriteLine("Content: {0}, SdpMid: {1}, SdpMlineIndex: {2}", candidate.Content, candidate.SdpMid, candidate.SdpMlineIndex);
                try
                {
                    Console.WriteLine("Candidate to send: Content: {0}, SdpMid: {1}, SdpMlineIndex: {2}", candidate.Content, candidate.SdpMid, candidate.SdpMlineIndex);
                    signaling.Send(candidate.ToABJson());
                }
                catch (Exception e)
                {
                    Console.WriteLine("Error to send local ice candidate");
                }
            };
            //videoTrackSource.I420AVideoFrameReady += (frame) =>
            //{
            //    Console.WriteLine("Argb32 frame ready. {0} : {1}", frame.width, frame.height);
            //    Console.WriteLine("DataA: {0}, DataU: {1}, DataV: {2}, DataY: {3}", Marshal.SizeOf(frame.dataA),
            //                        Marshal.SizeOf(frame.dataU),
            //                        Marshal.SizeOf(frame.dataV),
            //                        Marshal.SizeOf(frame.dataY));
            //};

            signaling.OnMessage += async(sender, message) =>
            {
                (string header, string correct_message) = message.Data.DivideHeaderAndOriginalJSON();
                Console.WriteLine("Correct message: {0}", correct_message);
                Console.WriteLine("Header: {0}", header);
                if (header == "{\"data\":{\"getRemoteMedia\":" && correct_message == "true")
                {
                    Console.WriteLine("Create local video track...");
                    var trackSettings = new LocalVideoTrackInitConfig {
                        trackName = "webcam_track"
                    };
                    localVideoTrack = LocalVideoTrack.CreateFromSource(videoTrackSource, new LocalVideoTrackInitConfig {
                        trackName = "webcam_track"
                    });
                    Console.WriteLine("Create video transceiver and add webcam track...");
                    TransceiverInitSettings option = new TransceiverInitSettings();
                    option.Name      = "webcam_track";
                    option.StreamIDs = new List <string> {
                        "webcam_name"
                    };
                    videoTransceiver = pc.AddTransceiver(MediaKind.Video, option);
                    videoTransceiver.DesiredDirection = Transceiver.Direction.SendOnly;
                    videoTransceiver.LocalVideoTrack  = localVideoTrack;

                    bool OfferCreated = pc.CreateOffer();
                    Console.WriteLine("OfferCreated? {0}", OfferCreated);
                }
                //Console.WriteLine(message.Data);
                if (header.IndexOf("candidate") != -1 && correct_message != "null")
                {
                    try
                    {
                        var candidate = JsonSerializer.Deserialize <ICEJavaScriptNotation>(correct_message);
                        Console.WriteLine("Content of ice: {0}, SdpMid: {1}, SdpMLineIndex: {2}", candidate.candidate, candidate.sdpMid, candidate.sdpMLineIndex);
                        pc.AddIceCandidate(candidate.ToMRNetCoreNotation());
                        Console.WriteLine("Deserialized by ice_candidate");
                        //return;
                    }
                    catch (Exception)
                    {
                        Console.WriteLine("Could not deserialize as ice candidate");
                    }
                }

                if (header.IndexOf("description") != -1)
                {
                    try
                    {
                        SdpMessage received_description = JsonSerializer.Deserialize <SDPJavaScriptNotation>(correct_message).ToMRNetCoreNotation();
                        await pc.SetRemoteDescriptionAsync(received_description);

                        if (received_description.Type == SdpMessageType.Offer)
                        {
                            bool res = pc.CreateAnswer();
                            Console.WriteLine("Answer created? {0}", res);
                        }
                        Console.WriteLine("Deserialized by sdp_message");
                    }
                    catch (Exception)
                    {
                        Console.WriteLine("Could not deserialize as sdp message");
                    }
                }
            };


            pc.Connected += () =>
            {
                Console.WriteLine("Connected");
            };
            pc.IceStateChanged += (IceConnectionState newState) =>
            {
                if (newState == IceConnectionState.Disconnected)
                {
                    Console.WriteLine("Disconected");
                }
            };


            signaling.Connect();
            if (!video_translator)
            {
                signaling.Send("{\"data\":{\"getRemoteMedia\":true}}");
            }

            //Console.WriteLine("Press a key to terminate the application...");
            Console.ReadKey(true);
            Console.WriteLine("Program termined.");
            file?.Close();
            pc?.Close();
            signaling?.Close();
            //arduino?.Close();
            //(var a, var b) = ConvertString("{\"data\":{\"candidate\":null}}");
            //Console.WriteLine("{0}, {1}", a, b);
        }
コード例 #8
0
 public void Close()
 {
     _peerConnection.Close();
 }
コード例 #9
0
        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);
        }
コード例 #10
0
        public void TearDownConnection()
        {
            // Unregister all callbacks
            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;

            Assert.IsFalse(exchangePending_);
            exchangeCompleted_.Dispose();
            exchangeCompleted_ = null;

            // Clean-up callback events
            dataChannelAddedEvent1_.Dispose();
            dataChannelAddedEvent1_ = null;
            dataChannelRemovedEvent1_.Dispose();
            dataChannelRemovedEvent1_ = null;
            audioTrackAddedEvent1_.Dispose();
            audioTrackAddedEvent1_ = null;
            audioTrackRemovedEvent1_.Dispose();
            audioTrackRemovedEvent1_ = null;
            audioTrackAddedEvent2_.Dispose();
            audioTrackAddedEvent2_ = null;
            audioTrackRemovedEvent2_.Dispose();
            audioTrackRemovedEvent2_ = null;
            videoTrackAddedEvent1_.Dispose();
            videoTrackAddedEvent1_ = null;
            videoTrackRemovedEvent1_.Dispose();
            videoTrackRemovedEvent1_ = null;
            videoTrackAddedEvent2_.Dispose();
            videoTrackAddedEvent2_ = null;
            videoTrackRemovedEvent2_.Dispose();
            videoTrackRemovedEvent2_ = null;
            renegotiationEvent1_.Dispose();
            renegotiationEvent1_ = null;
            renegotiationEvent2_.Dispose();
            renegotiationEvent2_ = null;
            iceConnectedEvent1_.Dispose();
            iceConnectedEvent1_ = null;
            iceConnectedEvent2_.Dispose();
            iceConnectedEvent2_ = null;
            remoteDescAppliedEvent1_.Dispose();
            remoteDescAppliedEvent1_ = null;
            remoteDescAppliedEvent2_.Dispose();
            remoteDescAppliedEvent2_ = null;
            connectedEvent1_.Dispose();
            connectedEvent1_ = null;
            connectedEvent2_.Dispose();
            connectedEvent2_ = null;

            // Destroy peers
            pc1_.Close();
            pc1_.Dispose();
            pc1_ = null;
            pc2_.Close();
            pc2_.Dispose();
            pc2_ = null;

            Assert.AreEqual(0, Library.ReportLiveObjects());
        }
コード例 #11
0
 private async void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
 {
     _peerConnection.Close();
     _peerConnection.Dispose();
     await _hubConnection.InvokeAsync("LeaveRoom", SignallerConstants.RoomName);
 }
コード例 #12
0
        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);
            }
        }