public void RegisterStartWithCustomHeaderTest()
        {
            logger.LogDebug("--> " + System.Reflection.MethodBase.GetCurrentMethod().Name);
            logger.BeginScope(System.Reflection.MethodBase.GetCurrentMethod().Name);

            SIPTransport   transport = new SIPTransport();
            MockSIPChannel channel   = new MockSIPChannel(new IPEndPoint(IPAddress.Any, 0));

            transport.AddSIPChannel(channel);
            SIPRegistrationUserAgent userAgent = new SIPRegistrationUserAgent(
                transport,
                null,
                new SIPURI("alice", "192.168.11.50", null, SIPSchemesEnum.sip, SIPProtocolsEnum.udp),
                "alice",
                "password123",
                null,
                "192.168.11.50",
                new SIPURI(SIPSchemesEnum.sip, IPAddress.Any, 0),
                120,
                null,
                new[] { "My-Header: value" });

            userAgent.Start();

            channel.SIPMessageSent.WaitOne(5000);
            Assert.Contains("My-Header: value", channel.LastSIPMessageSent);

            userAgent.Stop();
        }
Пример #2
0
        /// <summary>
        /// An asynchronous task that attempts to initiate a registration.
        /// </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 Task <bool> InitiateRegisterTaskAsync(SIPTransport sipTransport, SIPURI dst)
        {
            var ua = new SIPRegistrationUserAgent(sipTransport, "user", "password", dst.Host, 120);

            try
            {
                bool             result = false;
                ManualResetEvent mre    = new ManualResetEvent(false);

                ua.RegistrationFailed += (uri, err) =>
                {
                    result = false;
                    mre.Set();
                };
                ua.RegistrationTemporaryFailure += (uri, err) =>
                {
                    result = false;
                    mre.Set();
                };
                ua.RegistrationSuccessful += (uri) =>
                {
                    result = true;
                    mre.Set();
                };

                ua.Start();

                mre.WaitOne(TimeSpan.FromSeconds(2000));

                ua.Stop();

                return(Task.FromResult(result));
            }
            catch (Exception excp)
            {
                logger.LogError($"Exception InitiateRegisterTaskAsync. {excp.Message}");
                ua.Stop();
                return(Task.FromResult(false));
            }
        }
Пример #3
0
        static void Main()
        {
            Console.WriteLine("SIPSorcery registration user agent example.");
            Console.WriteLine("Press ctrl-c to exit.");

            AddConsoleLogger();

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

            EnableTraceLogs(sipTransport);

            // Create a client user agent to maintain a periodic registration with a SIP server.
            var regUserAgent = new SIPRegistrationUserAgent(sipTransport, USERNAME, PASSWORD, DOMAIN, EXPIRY);

            // Event handlers for the different stages of the registration.
            regUserAgent.RegistrationFailed           += (uri, err) => Log.LogError($"{uri.ToString()}: {err}");
            regUserAgent.RegistrationTemporaryFailure += (uri, msg) => Log.LogWarning($"{uri.ToString()}: {msg}");
            regUserAgent.RegistrationRemoved          += (uri) => Log.LogError($"{uri.ToString()} registration failed.");
            regUserAgent.RegistrationSuccessful       += (uri) => Log.LogInformation($"{uri.ToString()} registration succeeded.");

            // Start the thread to perform the initial registration and then periodically resend it.
            regUserAgent.Start();

            ManualResetEvent exitMRE = new ManualResetEvent(false);

            Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e)
            {
                e.Cancel = true;
                SIPSorcery.Sys.Log.Logger.LogInformation("Exiting...");
                exitMRE.Set();
            };

            exitMRE.WaitOne();

            regUserAgent.Stop();
            sipTransport.Shutdown();
            SIPSorcery.Net.DNSManager.Stop();
        }
        public void RegisterWithAdjustedRegisterHeaderTest()
        {
            logger.LogDebug("--> " + System.Reflection.MethodBase.GetCurrentMethod().Name);
            logger.BeginScope(System.Reflection.MethodBase.GetCurrentMethod().Name);

            SIPTransport   transport = new SIPTransport();
            MockSIPChannel channel   = new MockSIPChannel(new System.Net.IPEndPoint(IPAddress.Any, 0));

            transport.AddSIPChannel(channel);
            SIPRegistrationUserAgent userAgent = new SIPRegistrationUserAgent(
                transport,
                null,
                new SIPURI("alice", "192.168.11.50", null, SIPSchemesEnum.sip, SIPProtocolsEnum.udp),
                "alice",
                "password123",
                null,
                "192.168.11.50",
                new SIPURI(SIPSchemesEnum.sip, IPAddress.Any, 0),
                120,
                null,
                new[] { "My-Header: value" });
            SIPContactHeader testHeader = new SIPContactHeader("Contact Name", new SIPURI("User", "Host", "Param=Value"));

            userAgent.AdjustRegister = register =>
            {
                register.Header.Contact = new List <SIPContactHeader>
                {
                    testHeader
                };
                return(register);
            };

            userAgent.Start();

            channel.SIPMessageSent.WaitOne(5000);
            Assert.Contains(testHeader.ToString(), channel.LastSIPMessageSent);

            userAgent.Stop();
        }
Пример #5
0
        static void Main()
        {
            Console.WriteLine("SIPSorcery registration user agent example.");
            Console.WriteLine("Press ctrl-c to exit.");

            AddConsoleLogger();

            // Set up a default SIP transport.
            var sipTransport = new SIPTransport();
            var sipChannel   = new SIPUDPChannel(IPAddress.Any, 0);

            sipTransport.AddSIPChannel(sipChannel);

            EnableTraceLogs(sipTransport);

            // Create a client user agent to maintain a periodic registration with a SIP server.
            var regUserAgent = new SIPRegistrationUserAgent(
                sipTransport,
                "softphonesample",
                "password",
                "sipsorcery.com",
                120);

            int successCounter = 0;
            ManualResetEvent taskCompleteMre = new ManualResetEvent(false);

            // Event handlers for the different stages of the registration.
            regUserAgent.RegistrationFailed           += (uri, err) => SIPSorcery.Sys.Log.Logger.LogError($"{uri.ToString()}: {err}");
            regUserAgent.RegistrationTemporaryFailure += (uri, msg) => SIPSorcery.Sys.Log.Logger.LogWarning($"{uri.ToString()}: {msg}");
            regUserAgent.RegistrationRemoved          += (uri) => SIPSorcery.Sys.Log.Logger.LogError($"{uri.ToString()} registration failed.");
            regUserAgent.RegistrationSuccessful       += (uri) =>
            {
                SIPSorcery.Sys.Log.Logger.LogInformation($"{uri.ToString()} registration succeeded.");
                Interlocked.Increment(ref successCounter);
                SIPSorcery.Sys.Log.Logger.LogInformation($"Successful registrations {successCounter} of {SUCCESS_REGISTRATION_COUNT}.");

                if (successCounter == SUCCESS_REGISTRATION_COUNT)
                {
                    taskCompleteMre.Set();
                }
            };

            Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e)
            {
                e.Cancel = true;
                SIPSorcery.Sys.Log.Logger.LogInformation("Exiting...");
                taskCompleteMre.Set();
            };

            // Start the thread to perform the initial registration and then periodically resend it.
            regUserAgent.Start();

            taskCompleteMre.WaitOne();

            regUserAgent.Stop();
            if (sipTransport != null)
            {
                SIPSorcery.Sys.Log.Logger.LogInformation("Shutting down SIP transport...");
                sipTransport.Shutdown();
            }
            SIPSorcery.Net.DNSManager.Stop();
        }
Пример #6
0
        private const int SUCCESS_REGISTRATION_COUNT = 3;   // Number of successful registrations to attempt before exiting process.

        static void Main(string[] args)
        {
            Console.WriteLine("SIPSorcery registration user agent example.");
            Console.WriteLine("Press ctrl-c to exit.");

            // Logging configuration. Can be ommitted if internal SIPSorcery debug and warning messages are not required.
            var loggerFactory = new Microsoft.Extensions.Logging.LoggerFactory();
            var loggerConfig  = new LoggerConfiguration()
                                .Enrich.FromLogContext()
                                .MinimumLevel.Is(Serilog.Events.LogEventLevel.Debug)
                                .WriteTo.Console()
                                .CreateLogger();

            loggerFactory.AddSerilog(loggerConfig);
            SIPSorcery.Sys.Log.LoggerFactory = loggerFactory;

            // Set up a default SIP transport.
            var sipTransport = new SIPTransport(SIPDNSManager.ResolveSIPService, new SIPTransactionEngine());
            int port         = FreePort.FindNextAvailableUDPPort(SIPConstants.DEFAULT_SIP_PORT);
            var sipChannel   = new SIPUDPChannel(new IPEndPoint(LocalIPConfig.GetDefaultIPv4Address(), port));

            sipTransport.AddSIPChannel(sipChannel);

            // Create a client user agent to maintain a periodic registration with a SIP server.
            var regUserAgent = new SIPRegistrationUserAgent(
                sipTransport,
                "softphonesample",
                "password",
                "sipsorcery.com",
                120);

            int successCounter = 0;
            ManualResetEvent taskCompleteMre = new ManualResetEvent(false);

            // Event handlers for the different stages of the registration.
            regUserAgent.RegistrationFailed           += (uri, err) => SIPSorcery.Sys.Log.Logger.LogError($"{uri.ToString()}: {err}");
            regUserAgent.RegistrationTemporaryFailure += (uri, msg) => SIPSorcery.Sys.Log.Logger.LogWarning($"{uri.ToString()}: {msg}");
            regUserAgent.RegistrationRemoved          += (uri) => SIPSorcery.Sys.Log.Logger.LogError($"{uri.ToString()} registration failed.");
            regUserAgent.RegistrationSuccessful       += (uri) =>
            {
                SIPSorcery.Sys.Log.Logger.LogInformation($"{uri.ToString()} registration succeeded.");
                Interlocked.Increment(ref successCounter);
                SIPSorcery.Sys.Log.Logger.LogInformation($"Successful registrations {successCounter} of {SUCCESS_REGISTRATION_COUNT}.");

                if (successCounter == SUCCESS_REGISTRATION_COUNT)
                {
                    taskCompleteMre.Set();
                }
            };

            Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e)
            {
                e.Cancel = true;
                SIPSorcery.Sys.Log.Logger.LogInformation("Exiting...");
                taskCompleteMre.Set();
            };

            // Start the thread to perform the initial registration and then periodically resend it.
            regUserAgent.Start();

            taskCompleteMre.WaitOne();

            regUserAgent.Stop();
            if (sipTransport != null)
            {
                SIPSorcery.Sys.Log.Logger.LogInformation("Shutting down SIP transport...");
                sipTransport.Shutdown();
            }
            SIPSorcery.Net.DNSManager.Stop();
        }
Пример #7
0
        /// <summary>
        /// An asynchronous task that attempts to initiate a registration.
        /// </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 Task <bool> InitiateRegisterTaskAsync(SIPTransport sipTransport, SIPURI dst)
        {
            if (dst.User == null)
            {
                dst.User = "******";
            }

            var ua = new SIPRegistrationUserAgent(
                sipTransport,
                dst.User,
                "password",
                dst.ToString(),
                120);

            //var ua = new SIPRegistrationUserAgent(
            //    sipTransport,
            //    null,
            //    dst,
            //    dst.User,
            //    "password",
            //    null,
            //    dst.ToString(),
            //    new SIPURI(dst.Scheme, IPAddress.Any, 0),
            //    120,
            //    null);

            try
            {
                bool             result = false;
                ManualResetEvent mre    = new ManualResetEvent(false);

                ua.RegistrationFailed += (uri, err) =>
                {
                    result = false;
                    mre.Set();
                };
                ua.RegistrationTemporaryFailure += (uri, err) =>
                {
                    result = false;
                    mre.Set();
                };
                ua.RegistrationSuccessful += (uri) =>
                {
                    result = true;
                    mre.Set();
                };

                ua.Start();

                mre.WaitOne(TimeSpan.FromSeconds(2000));

                ua.Stop(false);

                return(Task.FromResult(result));
            }
            catch (Exception excp)
            {
                logger.LogError($"Exception InitiateRegisterTaskAsync. {excp.Message}");
                ua.Stop();
                return(Task.FromResult(false));
            }
        }
Пример #8
0
        static void Main(string[] args)
        {
            Console.WriteLine("SIPSorcery registration user agent example.");
            Console.WriteLine("Press ctrl-c to exit.");

            Log = AddConsoleLogger(LogEventLevel.Verbose);

            string server   = DEFAULT_SERVER;
            string username = DEFAULT_USERNAME;
            string password = DEFAULT_PASSWORD;
            int    expiry   = DEFAULT_EXPIRY;

            int posn = 0;

            while (posn < args?.Length && posn <= 3)
            {
                switch (posn)
                {
                case 0:
                    server = args[posn++].Trim();
                    break;

                case 1:
                    username = args[posn++].Trim();
                    break;

                case 2:
                    password = args[posn++].Trim();
                    break;

                case 3:
                    int.TryParse(args[posn++], out expiry);
                    break;
                }
            }

            Console.WriteLine("Attempting registration with:");
            Console.WriteLine($" server: {server}");
            Console.WriteLine($" username: {username}");
            Console.WriteLine($" expiry: {expiry}");

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

            sipTransport.EnableTraceLogs();

            // Create a client user agent to maintain a periodic registration with a SIP server.
            var regUserAgent = new SIPRegistrationUserAgent(sipTransport, username, password, server, expiry);

            // Event handlers for the different stages of the registration.
            regUserAgent.RegistrationFailed           += (uri, err) => Log.LogWarning($"{uri}: {err}");
            regUserAgent.RegistrationTemporaryFailure += (uri, msg) => Log.LogWarning($"{uri}: {msg}");
            regUserAgent.RegistrationRemoved          += (uri) => Log.LogWarning($"{uri} registration failed.");
            regUserAgent.RegistrationSuccessful       += (uri) => Log.LogInformation($"{uri} registration succeeded.");

            // Start the thread to perform the initial registration and then periodically resend it.
            regUserAgent.Start();

            ManualResetEvent exitMRE = new ManualResetEvent(false);

            Console.CancelKeyPress += (object sender, ConsoleCancelEventArgs e) =>
            {
                e.Cancel = true;
                Log.LogInformation("Exiting...");
                exitMRE.Set();
            };

            exitMRE.WaitOne();

            regUserAgent.Stop();

            // Allow for unregister request to be sent (REGISTER with 0 expiry)
            Task.Delay(1500).Wait();

            sipTransport.Shutdown();
        }
Пример #9
0
        static void Main(string[] args)
        {
            Console.WriteLine("SIPSorcery call hold example.");
            Console.WriteLine("Press ctrl-c to exit.");

            // Plumbing code to facilitate a graceful exit.
            CancellationTokenSource exitCts = new CancellationTokenSource(); // Cancellation token to stop the SIP transport and RTP stream.
            bool isCallHungup  = false;
            bool hasCallFailed = false;

            Utils.AddConsoleLogger();

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

            sipTransport.AddSIPChannel(new SIPUDPChannel(new IPEndPoint(IPAddress.Any, SIP_LISTEN_PORT)));

            //EnableTraceLogs(sipTransport);

            // Get the default speaker.
            var(audioOutEvent, audioOutProvider) = Utils.GetAudioOutputDevice();
            WaveInEvent waveInEvent = Utils.GetAudioInputDevice();



            RTPMediaSession RtpMediaSession = null;

            // Create a client user agent to maintain a periodic registration with a SIP server.
            var regUserAgent = new SIPRegistrationUserAgent(
                sipTransport,
                "1772",
                "aaa10800bd32115d86e548b8dfb21816",
                "10.84.0.250",
                120);

            ManualResetEvent taskCompleteMre = new ManualResetEvent(false);

            Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e)
            {
                e.Cancel = true;
                SIPSorcery.Sys.Log.Logger.LogInformation("Exiting...");
                taskCompleteMre.Set();
            };

            // Start the thread to perform the initial registration and then periodically resend it.
            regUserAgent.Start();


            // Create a client/server user agent to place a call to a remote SIP server along with event handlers for the different stages of the call.
            var userAgent = new SIPUserAgent(sipTransport, null);

            userAgent.ClientCallTrying  += (uac, resp) => Log.LogInformation($"{uac.CallDescriptor.To} Trying: {resp.StatusCode} {resp.ReasonPhrase}.");
            userAgent.ClientCallRinging += (uac, resp) => Log.LogInformation($"{uac.CallDescriptor.To} Ringing: {resp.StatusCode} {resp.ReasonPhrase}.");
            userAgent.ClientCallFailed  += (uac, err) =>
            {
                Log.LogWarning($"{uac.CallDescriptor.To} Failed: {err}");
                hasCallFailed = true;
                exitCts.Cancel();
            };
            userAgent.ClientCallAnswered += (uac, resp) =>
            {
                if (resp.Status == SIPResponseStatusCodesEnum.Ok)
                {
                    Log.LogInformation($"{uac.CallDescriptor.To} Answered: {resp.StatusCode} {resp.ReasonPhrase}.");
                    Utils.PlayRemoteMedia(RtpMediaSession, audioOutProvider);
                }
                else
                {
                    Log.LogWarning($"{uac.CallDescriptor.To} Answered: {resp.StatusCode} {resp.ReasonPhrase}.");
                    hasCallFailed = true;
                    exitCts.Cancel();
                }
            };
            userAgent.OnCallHungup += () =>
            {
                Log.LogInformation($"Call hungup by remote party.");
                exitCts.Cancel();
            };
            userAgent.ServerCallCancelled += (uas) => Log.LogInformation("Incoming call cancelled by caller.");

            sipTransport.SIPTransportRequestReceived += async(localEndPoint, remoteEndPoint, sipRequest) =>
            {
                if (sipRequest.Header.From != null &&
                    sipRequest.Header.From.FromTag != null &&
                    sipRequest.Header.To != null &&
                    sipRequest.Header.To.ToTag != null)
                {
                    // This is an in-dialog request that will be handled directly by a user agent instance.
                }
                else if (sipRequest.Method == SIPMethodsEnum.INVITE)
                {
                    if (userAgent?.IsCallActive == true)
                    {
                        Log.LogWarning($"Busy response returned for incoming call request from {remoteEndPoint}: {sipRequest.StatusLine}.");
                        // If we are already on a call return a busy response.
                        UASInviteTransaction uasTransaction = new UASInviteTransaction(sipTransport, sipRequest, null);
                        SIPResponse          busyResponse   = SIPResponse.GetResponse(sipRequest, SIPResponseStatusCodesEnum.BusyHere, null);
                        uasTransaction.SendFinalResponse(busyResponse);
                    }
                    else
                    {
                        Log.LogInformation($"Incoming call request from {remoteEndPoint}: {sipRequest.StatusLine}.");
                        var incomingCall = userAgent.AcceptCall(sipRequest);

                        RtpMediaSession = new RTPMediaSession(SDPMediaTypesEnum.audio, (int)SDPMediaFormatsEnum.PCMU, AddressFamily.InterNetwork);
                        RtpMediaSession.RemotePutOnHold   += () => Log.LogInformation("Remote call party has placed us on hold.");
                        RtpMediaSession.RemoteTookOffHold += () => Log.LogInformation("Remote call party took us off hold.");
                        await userAgent.Answer(incomingCall, RtpMediaSession);

                        Utils.PlayRemoteMedia(RtpMediaSession, audioOutProvider);
                        waveInEvent.StartRecording();

                        Log.LogInformation($"Answered incoming call from {sipRequest.Header.From.FriendlyDescription()} at {remoteEndPoint}.");
                    }
                }
                else
                {
                    Log.LogDebug($"SIP {sipRequest.Method} request received but no processing has been set up for it, rejecting.");
                    SIPResponse notAllowedResponse = SIPResponse.GetResponse(sipRequest, SIPResponseStatusCodesEnum.MethodNotAllowed, null);
                    await sipTransport.SendResponseAsync(notAllowedResponse);
                }
            };


            // Wire up the RTP send session to the audio output device.
            uint rtpSendTimestamp = 0;

            waveInEvent.DataAvailable += (object sender, WaveInEventArgs args) =>
            {
                byte[] sample      = new byte[args.Buffer.Length / 2];
                int    sampleIndex = 0;

                for (int index = 0; index < args.BytesRecorded; index += 2)
                {
                    var ulawByte = NAudio.Codecs.MuLawEncoder.LinearToMuLawSample(BitConverter.ToInt16(args.Buffer, index));
                    sample[sampleIndex++] = ulawByte;
                }

                if (RtpMediaSession != null)
                {
                    RtpMediaSession.SendAudioFrame(rtpSendTimestamp, sample);
                    rtpSendTimestamp += (uint)(8000 / waveInEvent.BufferMilliseconds);
                }
            };

            // At this point the call has been initiated and everything will be handled in an event handler.
            Task.Run(async() =>
            {
                try
                {
                    while (!exitCts.Token.WaitHandle.WaitOne(0))
                    {
                        var keyProps = Console.ReadKey();

                        if (keyProps.KeyChar == 'c')
                        {
                            if (!userAgent.IsCallActive)
                            {
                                RtpMediaSession = new RTPMediaSession(SDPMediaTypesEnum.audio, (int)SDPMediaFormatsEnum.PCMU, AddressFamily.InterNetwork);
                                RtpMediaSession.RemotePutOnHold   += () => Log.LogInformation("Remote call party has placed us on hold.");
                                RtpMediaSession.RemoteTookOffHold += () => Log.LogInformation("Remote call party took us off hold.");

                                var callDescriptor = Utils.GetCallDescriptor(DEFAULT_DESTINATION_SIP_URI);
                                await userAgent.InitiateCall(callDescriptor, RtpMediaSession);
                            }
                            else
                            {
                                Log.LogWarning("There is already an active call.");
                            }
                        }
                        else if (keyProps.KeyChar == 'h')
                        {
                            // Place call on/off hold.
                            if (userAgent.IsCallActive)
                            {
                                if (RtpMediaSession.LocalOnHold)
                                {
                                    Log.LogInformation("Taking the remote call party off hold.");
                                    RtpMediaSession.TakeOffHold();
                                }
                                else
                                {
                                    Log.LogInformation("Placing the remote call party on hold.");
                                    RtpMediaSession.PutOnHold();
                                }
                            }
                            else
                            {
                                Log.LogWarning("There is no active call to put on hold.");
                            }
                        }
                        else if (keyProps.KeyChar == 't')
                        {
                            if (userAgent.IsCallActive)
                            {
                                var transferURI = SIPURI.ParseSIPURI(TRANSFER_DESTINATION_SIP_URI);
                                bool result     = await userAgent.BlindTransfer(transferURI, TimeSpan.FromSeconds(TRANSFER_TIMEOUT_SECONDS), exitCts.Token);
                                if (result)
                                {
                                    // If the transfer was accepted the original call will already have been hungup.
                                    // Wait a second for the transfer NOTIFY request to arrive.
                                    await Task.Delay(1000);
                                    exitCts.Cancel();
                                }
                                else
                                {
                                    Log.LogWarning($"Transfer to {TRANSFER_DESTINATION_SIP_URI} failed.");
                                }
                            }
                            else
                            {
                                Log.LogWarning("There is no active call to transfer.");
                            }
                        }
                        else if (keyProps.KeyChar == 'q')
                        {
                            // Quit application.
                            exitCts.Cancel();
                        }
                    }
                }
                catch (Exception excp)
                {
                    SIPSorcery.Sys.Log.Logger.LogError($"Exception Key Press listener. {excp.Message}.");
                }
            });

            // Wait for a signal saying the call failed, was cancelled with ctrl-c or completed.
            exitCts.Token.WaitHandle.WaitOne();

            // Ctrl-c will gracefully exit the call at any point.
            Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e)
            {
                e.Cancel = true;
                exitCts.Cancel();
            };

            taskCompleteMre.WaitOne();

            regUserAgent.Stop();
            if (sipTransport != null)
            {
                SIPSorcery.Sys.Log.Logger.LogInformation("Shutting down SIP transport...");
                sipTransport.Shutdown();
            }
            SIPSorcery.Net.DNSManager.Stop();
        }