示例#1
0
        private static Task <RTCPeerConnection> CreatePeerConnection()
        {
            RTCConfiguration config = new RTCConfiguration
            {
                iceServers = new List <RTCIceServer> {
                    new RTCIceServer {
                        urls = STUN_URL
                    }
                }
            };
            var pc = new RTCPeerConnection(config);

            var testPatternSource    = new VideoTestPatternSource();
            var videoEncoderEndPoint = new VideoEncoderEndPoint();
            var audioSource          = new AudioExtrasSource(new AudioEncoder(), new AudioSourceOptions {
                AudioSource = AudioSourcesEnum.Music
            });

            MediaStreamTrack videoTrack = new MediaStreamTrack(videoEncoderEndPoint.GetVideoSourceFormats(), MediaStreamStatusEnum.SendRecv);

            pc.addTrack(videoTrack);
            MediaStreamTrack audioTrack = new MediaStreamTrack(audioSource.GetAudioSourceFormats(), MediaStreamStatusEnum.SendRecv);

            pc.addTrack(audioTrack);

            testPatternSource.OnVideoSourceRawSample        += videoEncoderEndPoint.ExternalVideoSourceRawSample;
            videoEncoderEndPoint.OnVideoSourceEncodedSample += pc.SendVideo;
            audioSource.OnAudioSourceEncodedSample          += pc.SendAudio;
            pc.OnVideoFormatsNegotiated += (formats) =>
                                           videoEncoderEndPoint.SetVideoSourceFormat(formats.First());
            pc.onconnectionstatechange += async(state) =>
            {
                logger.LogDebug($"Peer connection state change to {state}.");

                if (state == RTCPeerConnectionState.connected)
                {
                    await audioSource.StartAudio();

                    await testPatternSource.StartVideo();
                }
                else if (state == RTCPeerConnectionState.failed)
                {
                    pc.Close("ice disconnection");
                }
                else if (state == RTCPeerConnectionState.closed)
                {
                    await testPatternSource.CloseVideo();

                    await audioSource.CloseAudio();
                }
            };

            // Diagnostics.
            pc.OnReceiveReport += (re, media, rr) => logger.LogDebug($"RTCP Receive for {media} from {re}\n{rr.GetDebugSummary()}");
            pc.OnSendReport    += (media, sr) => logger.LogDebug($"RTCP Send for {media}\n{sr.GetDebugSummary()}");
            pc.GetRtpChannel().OnStunMessageReceived += (msg, ep, isRelay) => logger.LogDebug($"STUN {msg.Header.MessageType} received from {ep}.");
            pc.oniceconnectionstatechange += (state) => logger.LogDebug($"ICE connection state change to {state}.");

            return(Task.FromResult(pc));
        }
示例#2
0
        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            // Set up media sources.
            _maxSource = new FFmpegFileSource(MP4_PATH, true, new AudioEncoder());
            _maxSource.Initialise();

            _testPatternSource  = new VideoTestPatternSource();
            _testPatternEncoder = new FFmpegVideoEndPoint();
            _testPatternSource.OnVideoSourceRawSample += _testPatternEncoder.ExternalVideoSourceRawSample;

            _musicSource = new AudioExtrasSource(new AudioEncoder(),
                                                 new AudioSourceOptions {
                AudioSource = AudioSourcesEnum.Music
            });

            // The same  sources are used for all connected peers (broadcast) so the codecs need
            // to be restricted to a single well supported option.
            _musicSource.RestrictCodecs(new List <AudioCodecsEnum> {
                AudioCodecsEnum.PCMU
            });
            _maxSource.RestrictCodecs(new List <VideoCodecsEnum> {
                VIDEO_CODEC
            });
            _testPatternEncoder.RestrictCodecs(new List <VideoCodecsEnum> {
                VIDEO_CODEC
            });

            // Start web socket.
            _logger.LogInformation("Starting web socket server...");

            WebSocketServer webSocketServer = null;

            if (!string.IsNullOrWhiteSpace(_certificatePath))
            {
                if (!File.Exists(_certificatePath))
                {
                    throw new ApplicationException($"Certificate path could not be found {_certificatePath}.");
                }

                webSocketServer = new WebSocketServer(IPAddress.Any, WEBSOCKET_PORT, true);
                webSocketServer.SslConfiguration.ServerCertificate          = new X509Certificate2(_certificatePath);
                webSocketServer.SslConfiguration.CheckCertificateRevocation = false;
                webSocketServer.SslConfiguration.EnabledSslProtocols        = System.Security.Authentication.SslProtocols.Tls12;
            }
            else
            {
                webSocketServer = new WebSocketServer(IPAddress.Any, WEBSOCKET_PORT);
            }

            webSocketServer.AddWebSocketService <WebRTCWebSocketPeer>("/", (peer) => peer.CreatePeerConnection = () => CreatePeerConnection(null));
            webSocketServer.AddWebSocketService <WebRTCWebSocketPeer>($"/{MAX_URL}",
                                                                      (peer) => peer.CreatePeerConnection = () => CreatePeerConnection(MAX_URL));
            webSocketServer.Start();

            _logger.LogInformation($"Waiting for web socket connections on {webSocketServer.Address}:{webSocketServer.Port}...");

            await Task.Delay(Timeout.Infinite, stoppingToken);
        }
示例#3
0
        /// <summary>
        /// An asynchronous task that attempts to initiate a new call to a listening UAS.
        /// </summary>
        /// <param name="sipTransport">The transport object to use for the send.</param>
        /// <param name="dst">The destination end point to send the request to.</param>
        /// <returns>True if the expected response was received, false otherwise.</returns>
        private static async Task <bool> InitiateCallTaskAsync(SIPTransport sipTransport, SIPURI dst)
        {
            //UdpClient hepClient = new UdpClient(0, AddressFamily.InterNetwork);

            try
            {
                //sipTransport.SIPRequestOutTraceEvent += (localEP, remoteEP, req) =>
                //{
                //    logger.LogDebug($"Request sent: {localEP}->{remoteEP}");
                //    logger.LogDebug(req.ToString());

                //    //var hepBuffer = HepPacket.GetBytes(localEP, remoteEP, DateTimeOffset.Now, 333, "myHep", req.ToString());
                //    //hepClient.SendAsync(hepBuffer, hepBuffer.Length, "192.168.11.49", 9060);
                //};

                //sipTransport.SIPResponseInTraceEvent += (localEP, remoteEP, resp) =>
                //{
                //    logger.LogDebug($"Response received: {localEP}<-{remoteEP}");
                //    logger.LogDebug(resp.ToString());

                //    //var hepBuffer = HepPacket.GetBytes(remoteEP, localEP, DateTimeOffset.Now, 333, "myHep", resp.ToString());
                //    //hepClient.SendAsync(hepBuffer, hepBuffer.Length, "192.168.11.49", 9060);
                //};

                var ua = new SIPUserAgent(sipTransport, null);
                ua.ClientCallTrying   += (uac, resp) => logger.LogInformation($"{uac.CallDescriptor.To} Trying: {resp.StatusCode} {resp.ReasonPhrase}.");
                ua.ClientCallRinging  += (uac, resp) => logger.LogInformation($"{uac.CallDescriptor.To} Ringing: {resp.StatusCode} {resp.ReasonPhrase}.");
                ua.ClientCallFailed   += (uac, err, resp) => logger.LogWarning($"{uac.CallDescriptor.To} Failed: {err}");
                ua.ClientCallAnswered += (uac, resp) => logger.LogInformation($"{uac.CallDescriptor.To} Answered: {resp.StatusCode} {resp.ReasonPhrase}.");

                var audioOptions = new AudioSourceOptions {
                    AudioSource = AudioSourcesEnum.Silence
                };
                var audioExtrasSource = new AudioExtrasSource(new AudioEncoder(), audioOptions);
                audioExtrasSource.RestrictCodecs(new List <AudioCodecsEnum> {
                    AudioCodecsEnum.PCMU
                });
                var voipMediaSession = new VoIPMediaSession(new MediaEndPoints {
                    AudioSource = audioExtrasSource
                });

                var result = await ua.Call(dst.ToString(), null, null, voipMediaSession);

                ua.Hangup();

                await Task.Delay(200);

                return(result);
            }
            catch (Exception excp)
            {
                logger.LogError($"Exception InitiateCallTaskAsync. {excp.Message}");
                return(false);
            }
        }
示例#4
0
    private Task <SIPSorcery.Net.RTCPeerConnection> CreatePeerConnection()
    {
        var pc = new SIPSorcery.Net.RTCPeerConnection(null);

        // Set up sources and hook up send events to peer connection.
        AudioExtrasSource audioSrc = new AudioExtrasSource(new AudioEncoder(), new AudioSourceOptions {
            AudioSource = AudioSourcesEnum.None
        });

        audioSrc.OnAudioSourceEncodedSample += pc.SendAudio;
        //var testPatternSource = new VideoTestPatternSource();
        //testPatternSource.SetMaxFrameRate(true);
        //testPatternSource.OnVideoSourceRawSample += VideoEncoderEndPoint.ExternalVideoSourceRawSample;
        VideoEncoderEndPoint.OnVideoSourceEncodedSample += pc.SendVideo;

        // Add tracks.
        var audioTrack = new SIPSorcery.Net.MediaStreamTrack(audioSrc.GetAudioSourceFormats(), SIPSorcery.Net.MediaStreamStatusEnum.SendOnly);

        pc.addTrack(audioTrack);
        var videoTrack = new SIPSorcery.Net.MediaStreamTrack(VideoEncoderEndPoint.GetVideoSourceFormats(), SIPSorcery.Net.MediaStreamStatusEnum.SendOnly);

        pc.addTrack(videoTrack);

        // Handlers to set the codecs to use on the sources once the SDP negotiation is complete.
        pc.OnVideoFormatsNegotiated += (sdpFormat) => VideoEncoderEndPoint.SetVideoSourceFormat(SIPSorcery.Net.SDPMediaFormatInfo.GetVideoCodecForSdpFormat(sdpFormat.First().FormatCodec));
        pc.OnAudioFormatsNegotiated += (sdpFormat) =>
                                       audioSrc.SetAudioSourceFormat(SIPSorcery.Net.SDPMediaFormatInfo.GetAudioCodecForSdpFormat(sdpFormat.First().FormatCodec));

        pc.OnTimeout += (mediaType) => logger.LogDebug($"Timeout on media {mediaType}.");
        pc.oniceconnectionstatechange += (state) => logger.LogDebug($"ICE connection state changed to {state}.");
        pc.onconnectionstatechange    += async(state) =>
        {
            logger.LogDebug($"Peer connection connected changed to {state}.");
            if (state == SIPSorcery.Net.RTCPeerConnectionState.connected)
            {
                await audioSrc.StartAudio();

                //await testPatternSource.StartVideo();
            }
            else if (state == SIPSorcery.Net.RTCPeerConnectionState.closed || state == SIPSorcery.Net.RTCPeerConnectionState.failed)
            {
                await audioSrc.CloseAudio();

                //await testPatternSource.CloseVideo();
            }
        };

        pc.GetRtpChannel().OnStunMessageReceived += (msg, ep, isRelay) =>
        {
            bool hasUseCandidate = msg.Attributes.Any(x => x.AttributeType == SIPSorcery.Net.STUNAttributeTypesEnum.UseCandidate);
            logger.LogDebug($"STUN {msg.Header.MessageType} received from {ep}, use candidate {hasUseCandidate}.");
        };

        return(Task.FromResult(pc));
    }
示例#5
0
        static async Task Main()
        {
            Console.WriteLine("SIPSorcery Convert Audio");

            Log = AddConsoleLogger();

            //WaveFormatConversionStream converter = new WaveFormatConversionStream(_format_s16le48k, )
            _waveFile = new WaveFileWriter("output_s16le48k.mp3", _format_s16le48k);

            var sipTransport = new SIPTransport();
            var userAgent    = new SIPUserAgent(sipTransport, null);

            userAgent.OnCallHungup += (dialog) =>
            {
                Console.WriteLine("Call hungup.");
                _waveFile?.Close();
            };

            //EnableTraceLogs(sipTransport);

            var audioOptions = new AudioSourceOptions {
                AudioSource = AudioSourcesEnum.Silence
            };
            AudioExtrasSource audioExtrasSource = new AudioExtrasSource(new AudioEncoder(), audioOptions);

            audioExtrasSource.RestrictFormats((format) => format.Codec == AudioCodecsEnum.PCMU);
            var rtpSession = new VoIPMediaSession(new MediaEndPoints {
                AudioSource = audioExtrasSource
            });

            rtpSession.OnAudioFormatsNegotiated += (formats) =>
            {
                _ratio = (double)(OUT_SAMPLE_RATE / formats.First().RtpClockRate);
            };
            rtpSession.OnRtpPacketReceived += RtpSession_OnRtpPacketReceived;

            // Place the call and wait for the result.
            bool callResult = await userAgent.Call(DESTINATION, null, null, rtpSession);

            Console.WriteLine($"Call result {((callResult) ? "success" : "failure")}.");

            Console.WriteLine("press any key to exit...");
            Console.Read();

            if (userAgent.IsCallActive)
            {
                Console.WriteLine("Hanging up.");
                userAgent.Hangup();
            }

            // Clean up.
            sipTransport.Shutdown();
        }
示例#6
0
        private static async Task <RTCPeerConnection> SendSDPOffer(WebSocketContext context)
        {
            logger.LogDebug($"Web socket client connection from {context.UserEndPoint}.");

            var pc = new RTCPeerConnection(null);

            AudioExtrasSource audioSource = new AudioExtrasSource(new AudioEncoder());

            audioSource.OnAudioSourceEncodedSample += pc.SendAudio;

            MediaStreamTrack audioTrack = new MediaStreamTrack(audioSource.GetAudioSourceFormats(), MediaStreamStatusEnum.SendOnly);

            pc.addTrack(audioTrack);

            pc.OnAudioFormatsNegotiated += (sdpFormat) =>
                                           audioSource.SetAudioSourceFormat(SDPMediaFormatInfo.GetAudioCodecForSdpFormat(sdpFormat.First().FormatCodec));
            pc.OnReceiveReport            += RtpSession_OnReceiveReport;
            pc.OnSendReport               += RtpSession_OnSendReport;
            pc.OnTimeout                  += (mediaType) => pc.Close("remote timeout");
            pc.oniceconnectionstatechange += (state) => logger.LogDebug($"ICE connection state change to {state}.");

            pc.onconnectionstatechange += (state) =>
            {
                logger.LogDebug($"Peer connection state change to {state}.");

                if (state == RTCPeerConnectionState.connected)
                {
                    audioSource.SetSource(new AudioSourceOptions {
                        AudioSource = AudioSourcesEnum.SineWave
                    });
                }
                else if (state == RTCPeerConnectionState.disconnected || state == RTCPeerConnectionState.failed)
                {
                    pc.Close("remote disconnection");
                }
                else if (state == RTCPeerConnectionState.closed)
                {
                    audioSource?.CloseAudio();
                    pc.OnReceiveReport -= RtpSession_OnReceiveReport;
                    pc.OnSendReport    -= RtpSession_OnSendReport;
                }
            };

            var offerSdp = pc.createOffer(null);
            await pc.setLocalDescription(offerSdp);

            logger.LogDebug($"Sending SDP offer to client {context.UserEndPoint}.");
            logger.LogDebug(offerSdp.sdp);

            context.WebSocket.Send(offerSdp.sdp);

            return(pc);
        }
        private VoIPMediaSession CreateMockVoIPMediaEndPoint(Func <AudioFormat, bool> audioFormatFilter = null)
        {
            var audioSource = new AudioExtrasSource();

            audioSource.RestrictFormats(audioFormatFilter);

            MediaEndPoints mockEndPoints = new MediaEndPoints
            {
                AudioSource = audioSource
            };

            return(new VoIPMediaSession(mockEndPoints));
        }
示例#8
0
        private VoIPMediaSession CreateMockVoIPMediaEndPoint(List <AudioCodecsEnum> supportedCodecs = null)
        {
            var audioSource = new AudioExtrasSource();

            audioSource.RestrictCodecs(supportedCodecs);

            MediaEndPoints mockEndPoints = new MediaEndPoints
            {
                AudioSource = audioSource
            };

            return(new VoIPMediaSession(mockEndPoints));
        }
示例#9
0
        private static Task <RTCPeerConnection> CreatePeerConnection()
        {
            RTCConfiguration config = new RTCConfiguration
            {
                iceServers = new List <RTCIceServer> {
                    new RTCIceServer {
                        urls = STUN_URL
                    }
                }
            };
            var pc = new RTCPeerConnection(config);

            AudioExtrasSource audioSource = new AudioExtrasSource(new AudioEncoder(), new AudioSourceOptions {
                AudioSource = AudioSourcesEnum.SineWave
            });

            audioSource.OnAudioSourceEncodedSample += pc.SendAudio;

            MediaStreamTrack audioTrack = new MediaStreamTrack(audioSource.GetAudioSourceFormats(), MediaStreamStatusEnum.SendOnly);

            pc.addTrack(audioTrack);

            pc.OnAudioFormatsNegotiated += (sdpFormat) =>
                                           audioSource.SetAudioSourceFormat(SDPMediaFormatInfo.GetAudioCodecForSdpFormat(sdpFormat.First().FormatCodec));

            pc.onconnectionstatechange += async(state) =>
            {
                logger.LogDebug($"Peer connection state change to {state}.");

                if (state == RTCPeerConnectionState.connected)
                {
                    await audioSource.StartAudio();
                }
                else if (state == RTCPeerConnectionState.failed)
                {
                    pc.Close("ice disconnection");
                }
                else if (state == RTCPeerConnectionState.closed)
                {
                    await audioSource.CloseAudio();
                }
            };

            // Diagnostics.
            pc.OnReceiveReport += (re, media, rr) => logger.LogDebug($"RTCP Receive for {media} from {re}\n{rr.GetDebugSummary()}");
            pc.OnSendReport    += (media, sr) => logger.LogDebug($"RTCP Send for {media}\n{sr.GetDebugSummary()}");
            pc.GetRtpChannel().OnStunMessageReceived += (msg, ep, isRelay) => logger.LogDebug($"STUN {msg.Header.MessageType} received from {ep}.");
            pc.oniceconnectionstatechange += (state) => logger.LogDebug($"ICE connection state change to {state}.");

            return(Task.FromResult(pc));
        }
示例#10
0
        /// <summary>
        /// Example of how to create a basic RTP session object and hook up the event handlers.
        /// </summary>
        /// <param name="ua">The user agent the RTP session is being created for.</param>
        /// <param name="dst">THe destination specified on an incoming call. Can be used to
        /// set the audio source.</param>
        /// <returns>A new RTP session object.</returns>
        private static VoIPMediaSession CreateRtpSession(SIPUserAgent ua, string dst)
        {
            List <AudioCodecsEnum> codecs = new List <AudioCodecsEnum> {
                AudioCodecsEnum.PCMU, AudioCodecsEnum.PCMA, AudioCodecsEnum.G722
            };

            var audioSource = AudioSourcesEnum.SineWave;

            if (string.IsNullOrEmpty(dst) || !Enum.IsDefined(typeof(AudioSourcesEnum), dst) || !Enum.TryParse(dst, out audioSource))
            {
                audioSource = AudioSourcesEnum.Music;
            }

            Log.LogInformation($"RTP audio session source set to {audioSource}.");

            AudioExtrasSource audioExtrasSource = new AudioExtrasSource(new AudioEncoder(), new AudioSourceOptions {
                AudioSource = audioSource
            });

            audioExtrasSource.RestrictFormats(formats => codecs.Contains(formats.Codec));
            var rtpAudioSession = new VoIPMediaSession(new MediaEndPoints {
                AudioSource = audioExtrasSource
            });

            rtpAudioSession.AcceptRtpFromAny = true;

            // Wire up the event handler for RTP packets received from the remote party.
            rtpAudioSession.OnRtpPacketReceived += (ep, type, rtp) => OnRtpPacketReceived(ua, type, rtp);
            rtpAudioSession.OnTimeout           += (mediaType) =>
            {
                if (ua?.Dialogue != null)
                {
                    Log.LogWarning($"RTP timeout on call with {ua.Dialogue.RemoteTarget}, hanging up.");
                }
                else
                {
                    Log.LogWarning($"RTP timeout on incomplete call, closing RTP session.");
                }

                ua.Hangup();
            };

            return(rtpAudioSession);
        }
示例#11
0
        static async Task Main()
        {
            Console.WriteLine("SIPSorcery Asterisk + ICE Demo");

            AddConsoleLogger();
            CancellationTokenSource exitCts = new CancellationTokenSource();

            var sipTransport = new SIPTransport();

            EnableTraceLogs(sipTransport);

            var userAgent = new SIPUserAgent(sipTransport, null);

            userAgent.ClientCallFailed += (uac, error, sipResponse) => Console.WriteLine($"Call failed {error}.");
            userAgent.OnCallHungup     += async(dialog) =>
            {
                // Give time for the BYE response before exiting.
                await Task.Delay(1000);

                exitCts.Cancel();
            };

            var audioExtras = new AudioExtrasSource();

            audioExtras.SetSource(AudioSourcesEnum.PinkNoise);
            var testPattern = new VideoTestPatternSource(new VpxVideoEncoder());

            var pc = new RTCPeerConnection(null);

            pc.OnAudioFormatsNegotiated += (formats) => audioExtras.SetAudioSourceFormat(formats.First());
            pc.OnVideoFormatsNegotiated += (formats) => testPattern.SetVideoSourceFormat(formats.First());

            var audioTrack = new MediaStreamTrack(audioExtras.GetAudioSourceFormats(), MediaStreamStatusEnum.SendOnly);

            pc.addTrack(audioTrack);
            audioExtras.OnAudioSourceEncodedSample += pc.SendAudio;

            var videoTrack = new MediaStreamTrack(testPattern.GetVideoSourceFormats(), MediaStreamStatusEnum.SendOnly);

            pc.addTrack(videoTrack);
            testPattern.OnVideoSourceEncodedSample += pc.SendVideo;

            // Diagnostics.
            pc.OnReceiveReport += (re, media, rr) => Console.WriteLine($"RTCP Receive for {media} from {re}\n{rr.GetDebugSummary()}");
            pc.OnSendReport    += (media, sr) => Console.WriteLine($"RTCP Send for {media}\n{sr.GetDebugSummary()}");
            pc.GetRtpChannel().OnStunMessageReceived += (msg, ep, isRelay) => Console.WriteLine($"STUN {msg.Header.MessageType} received from {ep}.");
            pc.oniceconnectionstatechange += (state) => Console.WriteLine($"ICE connection state change to {state}.");

            // ICE connection state handler.
            pc.onconnectionstatechange += (state) =>
            {
                Console.WriteLine($"Peer connection state change to {state}.");

                if (state == RTCPeerConnectionState.connected)
                {
                    audioExtras.StartAudio();
                    testPattern.StartVideo();
                }
                else if (state == RTCPeerConnectionState.failed)
                {
                    if (userAgent.IsCallActive)
                    {
                        Console.WriteLine("ICE connection failed, hanging up active call.");
                        userAgent.Hangup();
                    }
                }
            };

            // Place the call and wait for the result.
            var callTask = userAgent.Call(DESTINATION, USERNAME, PASSWORD, pc);

            Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e)
            {
                e.Cancel = true;

                if (userAgent != null)
                {
                    if (userAgent.IsCalling || userAgent.IsRinging)
                    {
                        Console.WriteLine("Cancelling in progress call.");
                        userAgent.Cancel();
                    }
                    else if (userAgent.IsCallActive)
                    {
                        Console.WriteLine("Hanging up established call.");
                        userAgent.Hangup();
                    }
                }
                ;

                exitCts.Cancel();
            };

            Console.WriteLine("press ctrl-c to exit...");

            bool callResult = await callTask;

            if (callResult)
            {
                Console.WriteLine($"Call to {DESTINATION} succeeded.");
                exitCts.Token.WaitHandle.WaitOne();
            }
            else
            {
                Console.WriteLine($"Call to {DESTINATION} failed.");
            }

            Console.WriteLine("Exiting...");

            if (userAgent?.IsHangingUp == true)
            {
                Console.WriteLine("Waiting 1s for the call hangup or cancel to complete...");
                await Task.Delay(1000);
            }

            // Clean up.
            sipTransport.Shutdown();
        }
示例#12
0
        private static async Task <RTCPeerConnection> CreatePeerConnection()
        {
            RTCConfiguration config = new RTCConfiguration
            {
                iceServers = new List <RTCIceServer> {
                    new RTCIceServer {
                        urls = STUN_URL
                    }
                }
            };
            var pc = new RTCPeerConnection(config);

            WindowsVideoEndPoint winVideoEP = new WindowsVideoEndPoint(new VpxVideoEncoder(), WEBCAM_NAME);
            //WindowsVideoEndPoint winVideoEP = new WindowsVideoEndPoint(new FFmpegVideoEncoder(), WEBCAM_NAME);
            //WindowsVideoEndPoint winVideoEP = new WindowsVideoEndPoint(WEBCAM_NAME, 1920, 1080, 30);
            //winVideoEP.RestrictFormats(x => x.Codec == SIPSorceryMedia.Abstractions.V1.VideoCodecsEnum.H264);
            bool initResult = await winVideoEP.InitialiseVideoSourceDevice();

            if (!initResult)
            {
                throw new ApplicationException("Could not initialise video capture device.");
            }
            var audioSource = new AudioExtrasSource(new AudioEncoder(), new AudioSourceOptions {
                AudioSource = AudioSourcesEnum.Music
            });

            MediaStreamTrack videoTrack = new MediaStreamTrack(winVideoEP.GetVideoSourceFormats(), MediaStreamStatusEnum.SendRecv);

            pc.addTrack(videoTrack);
            MediaStreamTrack audioTrack = new MediaStreamTrack(audioSource.GetAudioSourceFormats(), MediaStreamStatusEnum.SendRecv);

            pc.addTrack(audioTrack);

            winVideoEP.OnVideoSourceEncodedSample  += pc.SendVideo;
            audioSource.OnAudioSourceEncodedSample += pc.SendAudio;
            pc.OnVideoFormatsNegotiated            += (videoFormats) =>
                                                      winVideoEP.SetVideoSourceFormat(videoFormats.First());
            pc.OnAudioFormatsNegotiated += (audioFormats) =>
                                           audioSource.SetAudioSourceFormat(audioFormats.First());

            pc.onconnectionstatechange += async(state) =>
            {
                logger.LogDebug($"Peer connection state change to {state}.");

                if (state == RTCPeerConnectionState.connected)
                {
                    await audioSource.StartAudio();

                    await winVideoEP.StartVideo();
                }
                else if (state == RTCPeerConnectionState.failed)
                {
                    pc.Close("ice disconnection");
                }
                else if (state == RTCPeerConnectionState.closed)
                {
                    await winVideoEP.CloseVideo();

                    await audioSource.CloseAudio();
                }
            };

            // Diagnostics.
            pc.OnReceiveReport += (re, media, rr) => logger.LogDebug($"RTCP Receive for {media} from {re}\n{rr.GetDebugSummary()}");
            pc.OnSendReport    += (media, sr) => logger.LogDebug($"RTCP Send for {media}\n{sr.GetDebugSummary()}");
            pc.GetRtpChannel().OnStunMessageReceived += (msg, ep, isRelay) => logger.LogDebug($"STUN {msg.Header.MessageType} received from {ep}.");
            pc.oniceconnectionstatechange += (state) => logger.LogDebug($"ICE connection state change to {state}.");

            return(pc);
        }
示例#13
0
        static void Main(string[] args)
        {
            Console.WriteLine("SIPSorcery user agent server example.");
            Console.WriteLine("Press h to hangup a call or ctrl-c to exit.");

            Log = AddConsoleLogger();

            IPAddress listenAddress     = IPAddress.Any;
            IPAddress listenIPv6Address = IPAddress.IPv6Any;

            if (args != null && args.Length > 0)
            {
                if (!IPAddress.TryParse(args[0], out var customListenAddress))
                {
                    Log.LogWarning($"Command line argument could not be parsed as an IP address \"{args[0]}\"");
                    listenAddress = IPAddress.Any;
                }
                else
                {
                    if (customListenAddress.AddressFamily == AddressFamily.InterNetwork)
                    {
                        listenAddress = customListenAddress;
                    }
                    if (customListenAddress.AddressFamily == AddressFamily.InterNetworkV6)
                    {
                        listenIPv6Address = customListenAddress;
                    }
                }
            }

            // Set up a default SIP transport.
            var sipTransport = new SIPTransport();

            var localhostCertificate = new X509Certificate2(SIPS_CERTIFICATE_PATH);

            // IPv4 channels.
            sipTransport.AddSIPChannel(new SIPUDPChannel(new IPEndPoint(listenAddress, SIP_LISTEN_PORT)));
            sipTransport.AddSIPChannel(new SIPTCPChannel(new IPEndPoint(listenAddress, SIP_LISTEN_PORT)));
            sipTransport.AddSIPChannel(new SIPTLSChannel(localhostCertificate, new IPEndPoint(listenAddress, SIPS_LISTEN_PORT)));
            //sipTransport.AddSIPChannel(new SIPWebSocketChannel(IPAddress.Any, SIP_WEBSOCKET_LISTEN_PORT));
            //sipTransport.AddSIPChannel(new SIPWebSocketChannel(IPAddress.Any, SIP_SECURE_WEBSOCKET_LISTEN_PORT, localhostCertificate));

            // IPv6 channels.
            sipTransport.AddSIPChannel(new SIPUDPChannel(new IPEndPoint(listenIPv6Address, SIP_LISTEN_PORT)));
            sipTransport.AddSIPChannel(new SIPTCPChannel(new IPEndPoint(listenIPv6Address, SIP_LISTEN_PORT)));
            sipTransport.AddSIPChannel(new SIPTLSChannel(localhostCertificate, new IPEndPoint(listenIPv6Address, SIPS_LISTEN_PORT)));
            //sipTransport.AddSIPChannel(new SIPWebSocketChannel(IPAddress.IPv6Any, SIP_WEBSOCKET_LISTEN_PORT));
            //sipTransport.AddSIPChannel(new SIPWebSocketChannel(IPAddress.IPv6Any, SIP_SECURE_WEBSOCKET_LISTEN_PORT, localhostCertificate));

            EnableTraceLogs(sipTransport);

            string executableDir = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);

            // To keep things a bit simpler this example only supports a single call at a time and the SIP server user agent
            // acts as a singleton
            SIPServerUserAgent      uas        = null;
            CancellationTokenSource rtpCts     = null; // Cancellation token to stop the RTP stream.
            VoIPMediaSession        rtpSession = null;

            // Because this is a server user agent the SIP transport must start listening for client user agents.
            sipTransport.SIPTransportRequestReceived += async(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPRequest sipRequest) =>
            {
                try
                {
                    if (sipRequest.Method == SIPMethodsEnum.INVITE)
                    {
                        Log.LogInformation($"Incoming call request: {localSIPEndPoint}<-{remoteEndPoint} {sipRequest.URI}.");

                        // Check there's a codec we support in the INVITE offer.
                        var        offerSdp       = SDP.ParseSDPDescription(sipRequest.Body);
                        IPEndPoint dstRtpEndPoint = SDP.GetSDPRTPEndPoint(sipRequest.Body);

                        if (offerSdp.Media.Any(x => x.Media == SDPMediaTypesEnum.audio && x.MediaFormats.Any(x => x.Key == (int)SDPWellKnownMediaFormatsEnum.PCMU)))
                        {
                            Log.LogDebug($"Client offer contained PCMU audio codec.");
                            AudioExtrasSource extrasSource = new AudioExtrasSource(new AudioEncoder(), new AudioSourceOptions {
                                AudioSource = AudioSourcesEnum.Music
                            });
                            rtpSession = new VoIPMediaSession(new MediaEndPoints {
                                AudioSource = extrasSource
                            });
                            rtpSession.AcceptRtpFromAny = true;

                            var setResult = rtpSession.SetRemoteDescription(SdpType.offer, offerSdp);

                            if (setResult != SetDescriptionResultEnum.OK)
                            {
                                // Didn't get a match on the codecs we support.
                                SIPResponse noMatchingCodecResponse = SIPResponse.GetResponse(sipRequest, SIPResponseStatusCodesEnum.NotAcceptableHere, setResult.ToString());
                                await sipTransport.SendResponseAsync(noMatchingCodecResponse);
                            }
                            else
                            {
                                // If there's already a call in progress hang it up. Of course this is not ideal for a real softphone or server but it
                                // means this example can be kept simpler.
                                if (uas?.IsHungup == false)
                                {
                                    uas?.Hangup(false);
                                }
                                rtpCts?.Cancel();
                                rtpCts = new CancellationTokenSource();

                                UASInviteTransaction uasTransaction = new UASInviteTransaction(sipTransport, sipRequest, null);
                                uas = new SIPServerUserAgent(sipTransport, null, uasTransaction, null);
                                uas.CallCancelled += (uasAgent) =>
                                {
                                    rtpCts?.Cancel();
                                    rtpSession.Close(null);
                                };
                                rtpSession.OnRtpClosed += (reason) => uas?.Hangup(false);
                                uas.Progress(SIPResponseStatusCodesEnum.Trying, null, null, null, null);
                                await Task.Delay(100);

                                uas.Progress(SIPResponseStatusCodesEnum.Ringing, null, null, null, null);
                                await Task.Delay(100);

                                var answerSdp = rtpSession.CreateAnswer(null);
                                uas.Answer(SDP.SDP_MIME_CONTENTTYPE, answerSdp.ToString(), null, SIPDialogueTransferModesEnum.NotAllowed);

                                await rtpSession.Start();
                            }
                        }
                    }
                    else if (sipRequest.Method == SIPMethodsEnum.BYE)
                    {
                        Log.LogInformation("Call hungup.");
                        SIPResponse byeResponse = SIPResponse.GetResponse(sipRequest, SIPResponseStatusCodesEnum.Ok, null);
                        await sipTransport.SendResponseAsync(byeResponse);

                        uas?.Hangup(true);
                        rtpSession?.Close(null);
                        rtpCts?.Cancel();
                    }
                    else if (sipRequest.Method == SIPMethodsEnum.SUBSCRIBE)
                    {
                        SIPResponse notAllowededResponse = SIPResponse.GetResponse(sipRequest, SIPResponseStatusCodesEnum.MethodNotAllowed, null);
                        await sipTransport.SendResponseAsync(notAllowededResponse);
                    }
                    else if (sipRequest.Method == SIPMethodsEnum.OPTIONS || sipRequest.Method == SIPMethodsEnum.REGISTER)
                    {
                        SIPResponse optionsResponse = SIPResponse.GetResponse(sipRequest, SIPResponseStatusCodesEnum.Ok, null);
                        await sipTransport.SendResponseAsync(optionsResponse);
                    }
                }
                catch (Exception reqExcp)
                {
                    Log.LogWarning($"Exception handling {sipRequest.Method}. {reqExcp.Message}");
                }
            };

            ManualResetEvent exitMre = new ManualResetEvent(false);

            Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e)
            {
                e.Cancel = true;

                Log.LogInformation("Exiting...");

                Hangup(uas).Wait();

                rtpSession?.Close(null);
                rtpCts?.Cancel();

                if (sipTransport != null)
                {
                    Log.LogInformation("Shutting down SIP transport...");
                    sipTransport.Shutdown();
                }

                exitMre.Set();
            };

            // Task to handle user key presses.
            Task.Run(() =>
            {
                try
                {
                    while (!exitMre.WaitOne(0))
                    {
                        var keyProps = Console.ReadKey();
                        if (keyProps.KeyChar == 'h' || keyProps.KeyChar == 'q')
                        {
                            Console.WriteLine();
                            Console.WriteLine("Hangup requested by user...");

                            Hangup(uas).Wait();

                            rtpSession?.Close(null);
                            rtpCts?.Cancel();
                        }

                        if (keyProps.KeyChar == 'q')
                        {
                            Log.LogInformation("Quitting...");

                            if (sipTransport != null)
                            {
                                Log.LogInformation("Shutting down SIP transport...");
                                sipTransport.Shutdown();
                            }

                            exitMre.Set();
                        }
                    }
                }
                catch (Exception excp)
                {
                    Log.LogError($"Exception Key Press listener. {excp.Message}.");
                }
            });

            exitMre.WaitOne();
        }
示例#14
0
        private static Task <RTCPeerConnection> Createpc(WebSocketContext context, RTCIceServer stunServer, bool relayOnly)
        {
            if (_peerConnection != null)
            {
                _peerConnection.Close("normal");
            }

            List <RTCCertificate> presetCertificates = null;

            if (File.Exists(LOCALHOST_CERTIFICATE_PATH))
            {
                var localhostCert = new X509Certificate2(LOCALHOST_CERTIFICATE_PATH, (string)null, X509KeyStorageFlags.Exportable);
                presetCertificates = new List <RTCCertificate> {
                    new RTCCertificate {
                        Certificate = localhostCert
                    }
                };
            }

            RTCConfiguration pcConfiguration = new RTCConfiguration
            {
                //certificates = presetCertificates,
                //X_RemoteSignallingAddress = (context != null) ? context.UserEndPoint.Address : null,
                iceServers = stunServer != null ? new List <RTCIceServer> {
                    stunServer
                } : null,
                iceTransportPolicy = relayOnly ? RTCIceTransportPolicy.relay : RTCIceTransportPolicy.all,
                //X_BindAddress = IPAddress.Any, // NOTE: Not reqd. Using this to filter out IPv6 addresses so can test with Pion.
            };

            _peerConnection = new RTCPeerConnection(pcConfiguration);

            //_peerConnection.GetRtpChannel().MdnsResolve = (hostname) => Task.FromResult(NetServices.InternetDefaultAddress);
            _peerConnection.GetRtpChannel().MdnsResolve = MdnsResolve;
            //_peerConnection.GetRtpChannel().OnStunMessageReceived += (msg, ep, isrelay) => logger.LogDebug($"STUN message received from {ep}, message type {msg.Header.MessageType}.");

            //var dc = _peerConnection.createDataChannel(DATA_CHANNEL_LABEL, null);
            //dc.onmessage += (msg) => logger.LogDebug($"data channel receive ({dc.label}-{dc.id}): {msg}");

            // Add a send-only audio track (this doesn't require any native libraries for encoding so is good for x-platform testing).
            AudioExtrasSource audioSource = new AudioExtrasSource(new AudioEncoder(), new AudioSourceOptions {
                AudioSource = AudioSourcesEnum.Music
            });

            audioSource.OnAudioSourceEncodedSample += _peerConnection.SendAudio;

            MediaStreamTrack audioTrack = new MediaStreamTrack(audioSource.GetAudioSourceFormats(), MediaStreamStatusEnum.SendOnly);

            _peerConnection.addTrack(audioTrack);

            _peerConnection.OnAudioFormatsNegotiated += (formats) =>
                                                        audioSource.SetAudioSourceFormat(formats.First());

            _peerConnection.onicecandidateerror     += (candidate, error) => logger.LogWarning($"Error adding remote ICE candidate. {error} {candidate}");
            _peerConnection.onconnectionstatechange += async(state) =>
            {
                logger.LogDebug($"Peer connection state changed to {state}.");

                if (state == RTCPeerConnectionState.disconnected || state == RTCPeerConnectionState.failed)
                {
                    _peerConnection.Close("remote disconnection");
                }

                if (state == RTCPeerConnectionState.connected)
                {
                    await audioSource.StartAudio();
                }
                else if (state == RTCPeerConnectionState.closed)
                {
                    await audioSource.CloseAudio();
                }
            };
            _peerConnection.OnReceiveReport += (re, media, rr) => logger.LogDebug($"RTCP Receive for {media} from {re}\n{rr.GetDebugSummary()}");
            _peerConnection.OnSendReport    += (media, sr) => logger.LogDebug($"RTCP Send for {media}\n{sr.GetDebugSummary()}");
            _peerConnection.OnRtcpBye       += (reason) => logger.LogDebug($"RTCP BYE receive, reason: {(string.IsNullOrWhiteSpace(reason) ? "<none>" : reason)}.");

            // Peer ICE connection state changes are for ICE events such as the STUN checks completing.
            _peerConnection.oniceconnectionstatechange += (state) => logger.LogDebug($"ICE connection state change to {state}.");

            _peerConnection.ondatachannel += (dc) =>
            {
                logger.LogDebug($"Data channel opened by remote peer, label {dc.label}, stream ID {dc.id}.");
                dc.onmessage += (msg) =>
                {
                    logger.LogDebug($"data channel ({dc.label}:{dc.id}): {msg}.");
                };
            };

            _peerConnection.onsignalingstatechange += () =>
            {
                if (_peerConnection.signalingState == RTCSignalingState.have_remote_offer)
                {
                    logger.LogDebug("Remote SDP:");
                    logger.LogDebug(_peerConnection.remoteDescription.sdp.ToString());
                }
                else if (_peerConnection.signalingState == RTCSignalingState.have_local_offer)
                {
                    logger.LogDebug("Local SDP:");
                    logger.LogDebug(_peerConnection.localDescription.sdp.ToString());
                }
            };

            return(Task.FromResult(_peerConnection));
        }
示例#15
0
        /// <summary>
        /// An asynchronous task that attempts to initiate a new call to a listening UAS.
        /// </summary>
        /// <param name="sipTransport">The transport object to use for the send.</param>
        /// <param name="dst">The destination end point to send the request to.</param>
        /// <returns>True if the expected response was received, false otherwise.</returns>
        private static async Task <bool> InitiateCallTaskAsync(SIPTransport sipTransport, SIPURI dst, Scenarios scenario)
        {
            //UdpClient hepClient = new UdpClient(0, AddressFamily.InterNetwork);

            try
            {
                //sipTransport.SIPRequestOutTraceEvent += (localEP, remoteEP, req) =>
                //{
                //    logger.LogDebug($"Request sent: {localEP}->{remoteEP}");
                //    logger.LogDebug(req.ToString());

                //    //var hepBuffer = HepPacket.GetBytes(localEP, remoteEP, DateTimeOffset.Now, 333, "myHep", req.ToString());
                //    //hepClient.SendAsync(hepBuffer, hepBuffer.Length, "192.168.11.49", 9060);
                //};

                //sipTransport.SIPResponseInTraceEvent += (localEP, remoteEP, resp) =>
                //{
                //    logger.LogDebug($"Response received: {localEP}<-{remoteEP}");
                //    logger.LogDebug(resp.ToString());

                //    //var hepBuffer = HepPacket.GetBytes(remoteEP, localEP, DateTimeOffset.Now, 333, "myHep", resp.ToString());
                //    //hepClient.SendAsync(hepBuffer, hepBuffer.Length, "192.168.11.49", 9060);
                //};

                var ua = new SIPUserAgent(sipTransport, null);
                ua.ClientCallTrying   += (uac, resp) => logger.LogInformation($"{uac.CallDescriptor.To} Trying: {resp.StatusCode} {resp.ReasonPhrase}.");
                ua.ClientCallRinging  += (uac, resp) => logger.LogInformation($"{uac.CallDescriptor.To} Ringing: {resp.StatusCode} {resp.ReasonPhrase}.");
                ua.ClientCallFailed   += (uac, err, resp) => logger.LogWarning($"{uac.CallDescriptor.To} Failed: {err}");
                ua.ClientCallAnswered += (uac, resp) => logger.LogInformation($"{uac.CallDescriptor.To} Answered: {resp.StatusCode} {resp.ReasonPhrase}.");

                var audioOptions = new AudioSourceOptions {
                    AudioSource = AudioSourcesEnum.Silence
                };
                var audioExtrasSource = new AudioExtrasSource(new AudioEncoder(), audioOptions);
                audioExtrasSource.RestrictFormats(format => format.Codec == AudioCodecsEnum.PCMU);
                var voipMediaSession = new VoIPMediaSession(new MediaEndPoints {
                    AudioSource = audioExtrasSource
                });

                var result = await ua.Call(dst.ToString(), null, null, voipMediaSession);

                if (scenario == Scenarios.uacw)
                {
                    // Wait for the remote party to hangup the call.
                    logger.LogDebug("Waiting for the remote party to hangup the call...");

                    ManualResetEvent hangupMre = new ManualResetEvent(false);
                    ua.OnCallHungup += (dialog) => hangupMre.Set();

                    hangupMre.WaitOne();

                    logger.LogDebug("Call hungup by remote party.");
                }
                else
                {
                    // We hangup the call after 1s.
                    await Task.Delay(1000);

                    ua.Hangup();
                }

                // Need a bit of time for the BYE to complete.
                await Task.Delay(500);

                return(result);
            }
            catch (Exception excp)
            {
                logger.LogError($"Exception InitiateCallTaskAsync. {excp.Message}");
                return(false);
            }
        }
示例#16
0
        private static RTCPeerConnection CreatePeerConnection()
        {
            RTCConfiguration config = new RTCConfiguration
            {
                iceServers = new List <RTCIceServer> {
                    new RTCIceServer {
                        urls = STUN_URL
                    }
                }
            };
            var pc = new RTCPeerConnection(config);

            WindowsVideoEndPoint winVideoEP = new WindowsVideoEndPoint();
            //WindowsVideoEndPoint winVideoEP = new WindowsVideoEndPoint(false, 640, 480, 30);
            //WindowsVideoEndPoint winVideoEP = new WindowsVideoEndPoint(false, 1920, 1080, 30);
            //await winVideoEP.InitialiseVideoSourceDevice();
            var audioSource = new AudioExtrasSource(new AudioEncoder(), new AudioSourceOptions {
                AudioSource = AudioSourcesEnum.Music
            });

            MediaStreamTrack videoTrack = new MediaStreamTrack(winVideoEP.GetVideoSourceFormats(), MediaStreamStatusEnum.SendRecv);

            pc.addTrack(videoTrack);
            MediaStreamTrack audioTrack = new MediaStreamTrack(audioSource.GetAudioSourceFormats(), MediaStreamStatusEnum.SendRecv);

            pc.addTrack(audioTrack);

            winVideoEP.OnVideoSourceEncodedSample  += pc.SendVideo;
            audioSource.OnAudioSourceEncodedSample += pc.SendAudio;
            pc.OnVideoFormatsNegotiated            += (sdpFormat) =>
                                                      winVideoEP.SetVideoSourceFormat(SDPMediaFormatInfo.GetVideoCodecForSdpFormat(sdpFormat.First().FormatCodec));
            pc.onconnectionstatechange += async(state) =>
            {
                logger.LogDebug($"Peer connection state change to {state}.");

                if (state == RTCPeerConnectionState.connected)
                {
                    await audioSource.StartAudio();

                    await winVideoEP.StartVideo();
                }
                else if (state == RTCPeerConnectionState.failed)
                {
                    pc.Close("ice disconnection");
                }
                else if (state == RTCPeerConnectionState.closed)
                {
                    await winVideoEP.CloseVideo();

                    await audioSource.CloseAudio();
                }
            };

            // Diagnostics.
            pc.OnReceiveReport += (re, media, rr) => logger.LogDebug($"RTCP Receive for {media} from {re}\n{rr.GetDebugSummary()}");
            pc.OnSendReport    += (media, sr) => logger.LogDebug($"RTCP Send for {media}\n{sr.GetDebugSummary()}");
            pc.GetRtpChannel().OnStunMessageReceived += (msg, ep, isRelay) => logger.LogDebug($"STUN {msg.Header.MessageType} received from {ep}.");
            pc.oniceconnectionstatechange += (state) => logger.LogDebug($"ICE connection state change to {state}.");

            return(pc);
        }