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(); }
private async Task Initialize() { await _sipTransportManager.InitialiseSIP(); for (int i = 0; i < SIP_CLIENT_COUNT; i++) { var mediaSessionFactory = new RTPMediaSessionManager(_mediaManager, _musicOnHold); var sipClient = new SIPClient(_sipTransportManager.SIPTransport, mediaSessionFactory); sipClient.CallAnswer += SIPCallAnswered; sipClient.CallEnded += ResetToCallStartState; sipClient.StatusMessage += (client, message) => { SetStatusText(m_signallingStatus, message); }; sipClient.RemotePutOnHold += RemotePutOnHold; sipClient.RemoteTookOffHold += RemoteTookOffHold; _sipClients.Add(sipClient); } string listeningEndPoints = null; foreach (var sipChannel in _sipTransportManager.SIPTransport.GetSIPChannels()) { SIPEndPoint sipChannelEP = sipChannel.ListeningSIPEndPoint.CopyOf(); sipChannelEP.ChannelID = null; listeningEndPoints += (listeningEndPoints == null) ? sipChannelEP.ToString() : $", {sipChannelEP}"; } listeningEndPoint.Content = $"Listening on: {listeningEndPoints}"; _sipRegistrationClient = new SIPRegistrationUserAgent( _sipTransportManager.SIPTransport, null, null, new SIPURI(m_sipUsername, m_sipServer, null, SIPSchemesEnum.sip, SIPProtocolsEnum.udp), m_sipUsername, m_sipPassword, null, m_sipServer, new SIPURI(m_sipUsername, IPAddress.Any.ToString(), null), 180, null, null, (message) => { logger.Debug(message); }); _sipRegistrationClient.Start(); }
/// <summary> /// Starts a registration agent for each of the supplied SIP accounts. /// </summary> /// <param name="sipTransport">The SIP transport to use for the registrations.</param> /// <param name="sipAccounts">The list of SIP accounts to create a registration for.</param> private static void StartRegistrations(SIPTransport sipTransport, List <SIPRegisterAccount> sipAccounts) { foreach (var sipAccount in sipAccounts) { var regUserAgent = new SIPRegistrationUserAgent(sipTransport, sipAccount.Username, sipAccount.Password, sipAccount.Domain, sipAccount.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(); _registrations.TryAdd($"{sipAccount.Username}@{sipAccount.Domain}", regUserAgent); } }
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; // If your default DNS server supports SRV records there is no need to set a specific DNS server. DNSManager.SetDNSServers(new List <IPEndPoint> { IPEndPoint.Parse("8.8.8.8:53") }); // 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"); // 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."); // Start the thread to perform the initial registration and then periodically resend it. regUserAgent.Start(); }
public void Init() { var port = FreePort.FindNextAvailableUDPPort(15090); transport = new SIPTransport(SIPDNSManager.ResolveSIPService, new SIPTransactionEngine()); publicIPAddress = STUNClient.GetPublicIPAddress("stun.ekiga.net"); localIPEndPoint = IpAddressLookup.QueryRoutingInterface(asterisk, port); var endpoint = new IPEndPoint(localIPEndPoint.Address, port); var channel = new SIPUDPChannel(endpoint); //channel.SIPMessageReceived += (SIPChannel sipChannel, SIPEndPoint remoteEndPoint, byte[] buffer) => { logger.Debug("Channel SIP message received " + channel.SIPChannelEndPoint + "<-" + remoteEndPoint); }; transport.AddSIPChannel(channel); for (var i = 0; i < numbers.Length; i++) { var number = numbers[i]; var password = passwords[i]; var registration = new SIPRegistrationUserAgent( transport, null, new SIPEndPoint(SIPProtocolsEnum.udp, publicIPAddress, port), new SIPURI(number, asterisk, null, SIPSchemesEnum.sip, SIPProtocolsEnum.udp), number, password, null, asterisk, new SIPURI(SIPSchemesEnum.sip, new SIPEndPoint(SIPProtocolsEnum.udp, publicIPAddress, port)), 180, null, null, (e) => { logger.Debug(e.Message); } ); logger.Debug($"{prefix} Registration attempt for {number}@{endpoint.Address}:{endpoint.Port}"); registration.RegistrationSuccessful += Registration_RegistrationSuccessful; registration.RegistrationFailed += Registration_RegistrationFailed; registration.Start(); registrations.Add(registration); } }
private SIPRegistrationUserAgent _sipRegistrationClient; // Can be used to register with an external SIP provider if incoming calls are required. public SoftPhone() { InitializeComponent(); // Do some UI initialisation. m_uasGrid.Visibility = Visibility.Collapsed; m_cancelButton.Visibility = Visibility.Collapsed; m_byeButton.Visibility = Visibility.Collapsed; // Set up the SIP client. It can receive calls and initiate outgoing calls. _sipClient = new SIPClient(); _sipClient.IncomingCall += SIPCallIncoming; _sipClient.CallAnswer += SIPCallAnswered; _sipClient.CallEnded += ResetToCallStartState; _sipClient.StatusMessage += (message) => { SetStatusText(m_signallingStatus, message); }; // Set up the Gingle client. _gingleClient = new GingleClient(); _gingleClient.CallEnded += ResetToCallStartState; _gingleClient.StatusMessage += (message) => { SetStatusText(m_signallingStatus, message); }; // Lookup and periodically check the public IP address of the host machine. _stunClient = new SoftphoneSTUNClient(); // Comment this out if you don't want the app to register with your SIP server. _sipRegistrationClient = new SIPRegistrationUserAgent( _sipClient.SIPClientTransport, null, null, new SIPURI(m_sipUsername, m_sipServer, null, SIPSchemesEnum.sip, SIPProtocolsEnum.udp), m_sipUsername, m_sipPassword, null, m_sipServer, new SIPURI(m_sipUsername, _sipClient.SIPClientTransport.GetDefaultSIPEndPoint().GetIPEndPoint().ToString(), null), 180, null, null, (message) => { logger.Debug(message); }); _sipRegistrationClient.Start(); //videoElement.NewVideoSample += new EventHandler<WPFMediaKit.DirectShow.MediaPlayers.VideoSampleArgs>(videoElement_NewVideoSample); }
private async void Initialise() { await _sipClient.InitialiseSIP(); _sipRegistrationClient = new SIPRegistrationUserAgent( _sipClient.SIPClientTransport, null, null, new SIPURI(m_sipUsername, m_sipServer, null, SIPSchemesEnum.sip, SIPProtocolsEnum.udp), m_sipUsername, m_sipPassword, null, m_sipServer, new SIPURI(m_sipUsername, _sipClient.SIPClientTransport.GetDefaultSIPEndPoint().GetIPEndPoint().ToString(), null), 180, null, null, (message) => { logger.Debug(message); }); _sipRegistrationClient.Start(); }
/// <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)); } }
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(); }
/// <summary> /// Initialises the SIP clients and transport. /// </summary> private async Task Initialize() { await _sipTransportManager.InitialiseSIP(); for (int i = 0; i < SIP_CLIENT_COUNT; i++) { var sipClient = new SIPClient(_sipTransportManager.SIPTransport); sipClient.CallAnswer += SIPCallAnswered; sipClient.CallEnded += ResetToCallStartState; sipClient.StatusMessage += (client, message) => { SetStatusText(m_signallingStatus, message); }; sipClient.RemotePutOnHold += RemotePutOnHold; sipClient.RemoteTookOffHold += RemoteTookOffHold; _sipClients.Add(sipClient); } string listeningEndPoints = null; foreach (var sipChannel in _sipTransportManager.SIPTransport.GetSIPChannels()) { SIPEndPoint sipChannelEP = sipChannel.ListeningSIPEndPoint.CopyOf(); sipChannelEP.ChannelID = null; listeningEndPoints += (listeningEndPoints == null) ? sipChannelEP.ToString() : $", {sipChannelEP}"; } listeningEndPoint.Content = $"Listening on: {listeningEndPoints}"; _sipRegistrationClient = new SIPRegistrationUserAgent( _sipTransportManager.SIPTransport, m_sipUsername, m_sipPassword, m_sipServer, REGISTRATION_EXPIRY); _sipRegistrationClient.Start(); }
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(); }
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(); }
/// <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)); } }
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(); }
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(); }