Exemple #1
0
        /// <summary>
        /// Places an outgoing SIP call.
        /// </summary>
        /// <param name="destination">The SIP URI to place a call to. The destination can be a full SIP URI in which case the all will
        /// be placed anonymously directly to that URI. Alternatively it can be just the user portion of a URI in which case it will
        /// be sent to the configured SIP server.</param>
        public async Task Call(string destination)
        {
            // Determine if this is a direct anonymous call or whether it should be placed using the pre-configured SIP server account.
            SIPURI callURI     = null;
            string sipUsername = null;
            string sipPassword = null;
            string fromHeader  = null;

            if (destination.Contains("@") || m_sipServer == null)
            {
                // Anonymous call direct to SIP server specified in the URI.
                callURI    = SIPURI.ParseSIPURIRelaxed(destination);
                fromHeader = (new SIPFromHeader(m_sipFromName, SIPURI.ParseSIPURI(SIPFromHeader.DEFAULT_FROM_URI), null)).ToString();
            }
            else
            {
                // This call will use the pre-configured SIP account.
                callURI     = SIPURI.ParseSIPURIRelaxed(destination + "@" + m_sipServer);
                sipUsername = m_sipUsername;
                sipPassword = m_sipPassword;
                fromHeader  = (new SIPFromHeader(m_sipFromName, new SIPURI(m_sipUsername, m_sipServer, null), null)).ToString();
            }

            StatusMessage(this, $"Starting call to {callURI}.");

            var lookupResult = await Task.Run(() =>
            {
                return(SIPDNSManager.ResolveSIPService(callURI, false));
            });

            if (lookupResult == null || lookupResult.LookupError != null)
            {
                StatusMessage(this, $"Call failed, could not resolve {callURI}.");
            }
            else
            {
                var dstEndpoint = lookupResult.GetSIPEndPoint();
                StatusMessage(this, $"Call progressing, resolved {callURI} to {dstEndpoint}.");
                System.Diagnostics.Debug.WriteLine($"DNS lookup result for {callURI}: {dstEndpoint}.");
                SIPCallDescriptor callDescriptor = new SIPCallDescriptor(sipUsername, sipPassword, callURI.ToString(), fromHeader, null, null, null, null, SIPCallDirection.Out, _sdpMimeContentType, null, null);

                var audioSrcOpts = new AudioOptions
                {
                    AudioSource       = AudioSourcesEnum.Microphone,
                    OutputDeviceIndex = m_audioOutDeviceIndex
                };
                var videoSrcOpts = new VideoOptions
                {
                    VideoSource           = VideoSourcesEnum.TestPattern,
                    SourceFile            = RtpAVSession.VIDEO_TESTPATTERN,
                    SourceFramesPerSecond = VIDEO_LIVE_FRAMES_PER_SECOND
                };
                MediaSession = new RtpAVSession(audioSrcOpts, videoSrcOpts);

                m_userAgent.RemotePutOnHold   += OnRemotePutOnHold;
                m_userAgent.RemoteTookOffHold += OnRemoteTookOffHold;

                await m_userAgent.InitiateCallAsync(callDescriptor, MediaSession);
            }
        }
        private void ProbeWorkers()
        {
            try {
                while (!m_exit)
                {
                    try {
                        SIPEndPoint       activeWorkerEndPoint = GetFirstHealthyEndPoint();
                        SIPCallDescriptor callDescriptor       = new SIPCallDescriptor(m_dispatcherUsername, null, "sip:" + m_dispatcherUsername + "@" + activeWorkerEndPoint.SocketEndPoint.ToString(),
                                                                                       "sip:" + m_dispatcherUsername + "@sipcalldispatcher", "sip:" + activeWorkerEndPoint.SocketEndPoint.ToString(), null, null, null, SIPCallDirection.Out, null, null, null);
                        SIPClientUserAgent uac = new SIPClientUserAgent(m_sipTransport, null, null, null, null);
                        uac.CallAnswered += DispatcherCallAnswered;
                        uac.CallFailed   += new SIPCallFailedDelegate(DispatcherCallFailed);
                        uac.Call(callDescriptor);
                    }
                    catch (Exception probeExcp) {
                        dispatcherLogger.Error("Exception SIPCallDispatcher Sending Probe. " + probeExcp.Message);
                    }

                    Thread.Sleep(PROBE_WORKER_CALL_PERIOD);
                }
            }
            catch (Exception excp) {
                logger.Error("Exception SIPCallDispatcher ProberWorkers. " + excp.Message);
            }
        }
Exemple #3
0
        /// <summary>
        /// Starts a call based on a single multi forward call leg.
        /// </summary>
        /// <param name="calls">The list of simultaneous forwards to attempt.</param>
        public void Start(List <SIPCallDescriptor> callDescriptors)
        {
            if (callDescriptors != null && callDescriptors.Count > 0)
            {
                for (int index = 0; index < callDescriptors.Count; index++)
                {
                    int availableThreads             = 0;
                    int ioCompletionThreadsAvailable = 0;
                    ThreadPool.GetAvailableThreads(out availableThreads, out ioCompletionThreadsAvailable);

                    if (availableThreads <= 0)
                    {
                        logger.Warn("The ThreadPool had no threads available in the pool to start a ForkCall leg, task will be queued.");
                    }

                    SIPCallDescriptor callDescriptor = callDescriptors[index];
                    FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "ForkCall commencing call leg to " + callDescriptor.Uri + ".", m_username));
                    ThreadPool.QueueUserWorkItem(delegate { StartNewCallAsync(callDescriptor); });
                }
            }
            else
            {
                CallLegCompleted();
            }
        }
 static void Main(string[] args)
 {
     try
     {
         // Configure the SIP transport layer.
         _sipTransport = new SIPTransport(SIPDNSManager.ResolveSIPService, new SIPTransactionEngine());
         // Use default options to set up a SIP channel.
         var localIP    = LocalIPConfig.GetDefaultIPv4Address();                      // Set this manually if needed.
         int port       = FreePort.FindNextAvailableUDPPort(_defaultSIPUdpPort);
         var sipChannel = new SIPUDPChannel(new IPEndPoint(localIP, port));
         _sipTransport.AddSIPChannel(sipChannel);
         SIPCallDescriptor           callDescriptor = new SIPCallDescriptor("test", null, "sip:[email protected]", "sip:[email protected]", null, null, null, null, SIPCallDirection.Out, null, null, null);
         SIPNonInviteClientUserAgent notifyUac      = new SIPNonInviteClientUserAgent(_sipTransport, null, callDescriptor, null, null, (monitorEvent) => { Console.WriteLine("Debug: " + monitorEvent.Message); });
         notifyUac.ResponseReceived += (resp) => { Console.WriteLine(resp.ToString()); };
         notifyUac.SendRequest(SIPMethodsEnum.NOTIFY);
         ManualResetEvent mre = new ManualResetEvent(false);
         mre.WaitOne();
     }
     catch (Exception excp)
     {
         Console.WriteLine("Exception Main. " + excp);
     }
     finally
     {
         Console.WriteLine("Press any key to exit...");
         Console.ReadLine();
     }
 }
Exemple #5
0
        /// <summary>
        /// Fired after each call leg forward attempt is completed.
        /// </summary>
        private void CallLegCompleted()
        {
            try
            {
                if (!m_callAnswered && !m_commandCancelled)
                {
                    if (m_switchCalls.Count > 0 || m_delayedCalls.Count > 0)
                    {
                        // There are still calls on this leg in progress.

                        // If there are no current calls then start the next delayed one.
                        if (m_switchCalls.Count == 0)
                        {
                            SIPCallDescriptor nextCall = null;
                            lock (m_delayedCalls)
                            {
                                foreach (SIPCallDescriptor call in m_delayedCalls)
                                {
                                    if (nextCall == null || nextCall.DelaySeconds > call.DelaySeconds)
                                    {
                                        nextCall = call;
                                    }
                                }
                            }

                            if (nextCall != null)
                            {
                                nextCall.DelayMRE.Set();
                            }
                        }
                    }
                    else if (m_priorityCallsQueue.Count != 0 && !m_callAnswered)
                    {
                        List <SIPCallDescriptor> nextPrioritycalls = m_priorityCallsQueue.Dequeue();
                        Start(nextPrioritycalls);
                    }
                    else if (CallFailed != null)
                    {
                        // No more call legs to attempt, or call has already been answered or cancelled.
                        if (m_lastFailureStatus != SIPResponseStatusCodesEnum.None)
                        {
                            CallFailed(m_lastFailureStatus, m_lastFailureReason, null);
                        }
                        else
                        {
                            CallFailed(SIPResponseStatusCodesEnum.TemporarilyUnavailable, "All forwards failed.", null);
                        }
                    }
                }
            }
            catch (Exception excp)
            {
                logger.Error("Exception CallLegCompleted. " + excp);
            }
        }
Exemple #6
0
        public void Start(string endpoint)
        {
            this.endpoint = endpoint;

            var caller   = "1003";
            var password = passwords[0];
            var port     = FreePort.FindNextAvailableUDPPort(15090);

            rtpChannel = new RTPChannel
            {
                DontTimeout    = true,
                RemoteEndPoint = new IPEndPoint(IPAddress.Parse(asterisk), port)
            };

            rtpChannel.SetFrameType(FrameTypesEnum.Audio);
            rtpChannel.ReservePorts(15000, 15090);
            rtpChannel.OnFrameReady += RtpChannel_OnFrameReady;

            uac = new SIPClientUserAgent(transport, null, null, null, null);

            var uri    = SIPURI.ParseSIPURIRelaxed($"{ endpoint }@{ asterisk }");
            var from   = (new SIPFromHeader(caller, new SIPURI(caller, asterisk, null), null)).ToString();
            var random = Crypto.GetRandomInt(5).ToString();
            var sdp    = new SDP
            {
                Version     = 2,
                Username    = "******",
                SessionId   = random,
                Address     = localIPEndPoint.Address.ToString(),
                SessionName = "redfox_" + random,
                Timing      = "0 0",
                Connection  = new SDPConnectionInformation(publicIPAddress.ToString())
            };

            var announcement = new SDPMediaAnnouncement
            {
                Media        = SDPMediaTypesEnum.audio,
                MediaFormats = new List <SDPMediaFormat>()
                {
                    new SDPMediaFormat((int)SDPMediaFormatsEnum.PCMU, "PCMU", 8000)
                },
                Port = rtpChannel.RTPPort
            };

            sdp.Media.Add(announcement);

            var descriptor = new SIPCallDescriptor(caller, password, uri.ToString(), from, null, null, null, null, SIPCallDirection.Out, SDP.SDP_MIME_CONTENTTYPE, sdp.ToString(), null);

            uac.CallTrying   += Uac_CallTrying;
            uac.CallRinging  += Uac_CallRinging;
            uac.CallAnswered += Uac_CallAnswered;
            uac.CallFailed   += Uac_CallFailed;

            uac.Call(descriptor);
        }
Exemple #7
0
        static async Task DialNumber()
        {
            string fromHeader = (new SIPFromHeader(USERNAME, new SIPURI(USERNAME, DOMAIN, null), null)).ToString();

            SIPCallDescriptor callDescriptor = new SIPCallDescriptor(USERNAME, PASSWORD, DEFAULT_CALL_DESTINATION, fromHeader, null, null, null, null, SIPCallDirection.Out, SDP.SDP_MIME_CONTENTTYPE, null, null);

            callDescriptor.CallId = "12028883999";

            userAgent = new SIPUserAgent(sipTransport, null);
            userAgent.ClientCallTrying   += (uac, resp) => Console.WriteLine($"{uac.CallDescriptor.To} Trying: {resp.StatusCode} {resp.ReasonPhrase}.");
            userAgent.ClientCallRinging  += (uac, resp) => Console.WriteLine($"{uac.CallDescriptor.To} Ringing: {resp.StatusCode} {resp.ReasonPhrase}.");
            userAgent.ClientCallFailed   += (uac, err, resp) => Console.WriteLine($"{uac.CallDescriptor.To} Failed: {err}, Status code: {resp?.StatusCode}");
            userAgent.ClientCallAnswered += (uac, resp) => Console.WriteLine($"{uac.CallDescriptor.To} Answered: {resp.StatusCode} {resp.ReasonPhrase}.");
            userAgent.OnDtmfTone         += (key, duration) => OnDtmfTone(userAgent, key, duration);
            userAgent.OnRtpEvent         += (evt, hdr) => Console.WriteLine($"rtp event {evt.EventID}, duration {evt.Duration}, end of event {evt.EndOfEvent}, timestamp {hdr.Timestamp}, marker {hdr.MarkerBit}.");
            userAgent.OnCallHungup       += OnHangup;

            var rtpSession = new RtpAVSession(
                new AudioOptions
            {
                AudioSource = AudioSourcesEnum.CaptureDevice,
                AudioCodecs = new List <SDPMediaFormatsEnum> {
                    SDPMediaFormatsEnum.PCMU, SDPMediaFormatsEnum.PCMA
                }
            },
                null);

            rtpSession.OnRtpPacketReceived += OnRtpPacketReceived;

            var callResult = await userAgent.Call(callDescriptor, rtpSession);

            Console.WriteLine($"Call result {((callResult) ? "success" : "failure")}.");
            if (callResult)
            {
                Console.WriteLine("Enter digits one after another");
                for (int i = 0; i < 11; i++)
                {
                    var p = Console.ReadLine();
                    await userAgent.SendDtmf(byte.Parse(p));
                }
            }
            Console.WriteLine("Enter ?");
            Console.ReadLine();
            await userAgent.SendDtmf(35);

            Thread.Sleep(60000);

            userAgent.Hangup();
            _waveFile.Dispose();
            Console.WriteLine("Hangup");
        }
Exemple #8
0
        /// <summary>
        /// Places an outgoing SIP call.
        /// </summary>
        /// <param name="destination">The SIP URI to place a call to. The destination can be a full SIP URI in which case the all will
        /// be placed anonymously directly to that URI. Alternatively it can be just the user portion of a URI in which case it will
        /// be sent to the configured SIP server.</param>
        public async Task Call(string destination)
        {
            // Determine if this is a direct anonymous call or whether it should be placed using the pre-configured SIP server account.
            SIPURI callURI     = null;
            string sipUsername = null;
            string sipPassword = null;
            string fromHeader  = null;

            if (destination.Contains("@") || m_sipServer == null)
            {
                // Anonymous call direct to SIP server specified in the URI.
                callURI    = SIPURI.ParseSIPURIRelaxed(destination);
                fromHeader = (new SIPFromHeader(m_sipFromName, SIPURI.ParseSIPURI(SIPFromHeader.DEFAULT_FROM_URI), null)).ToString();
            }
            else
            {
                // This call will use the pre-configured SIP account.
                callURI     = SIPURI.ParseSIPURIRelaxed(destination + "@" + m_sipServer);
                sipUsername = m_sipUsername;
                sipPassword = m_sipPassword;
                fromHeader  = (new SIPFromHeader(m_sipFromName, new SIPURI(m_sipUsername, m_sipServer, null), null)).ToString();
            }

            StatusMessage(this, $"Starting call to {callURI}.");

            var lookupResult = await Task.Run(() =>
            {
                return(SIPDNSManager.ResolveSIPService(callURI, false));
            });

            if (lookupResult == null || lookupResult.LookupError != null)
            {
                StatusMessage(this, $"Call failed, could not resolve {callURI}.");
            }
            else
            {
                var dstEndpoint = lookupResult.GetSIPEndPoint();
                StatusMessage(this, $"Call progressing, resolved {callURI} to {dstEndpoint}.");
                System.Diagnostics.Debug.WriteLine($"DNS lookup result for {callURI}: {dstEndpoint}.");
                SIPCallDescriptor callDescriptor = new SIPCallDescriptor(sipUsername, sipPassword, callURI.ToString(), fromHeader, null, null, null, null, SIPCallDirection.Out, _sdpMimeContentType, null, null);

                m_rtpMediaSessionManager.Create(dstEndpoint.Address.AddressFamily);
                m_rtpMediaSessionManager.RTPMediaSession.RemotePutOnHold   += OnRemotePutOnHold;
                m_rtpMediaSessionManager.RTPMediaSession.RemoteTookOffHold += OnRemoteTookOffHold;

                await m_userAgent.InitiateCall(callDescriptor, m_rtpMediaSessionManager.RTPMediaSession);
            }
        }
        /// <summary>
        /// Places an outgoing SIP call.
        /// </summary>
        /// <param name="destination">The SIP URI to place a call to. The destination can be a full SIP URI in which case the all will
        /// be placed anonymously directly to that URI. Alternatively it can be just the user portion of a URI in which case it will
        /// be sent to the configured SIP server.</param>
        public async Task Call(string destination)
        {
            // Determine if this is a direct anonymous call or whether it should be placed using the pre-configured SIP server account.
            SIPURI callURI     = null;
            string sipUsername = null;
            string sipPassword = null;
            string fromHeader  = null;

            if (destination.Contains("@") || m_sipServer == null)
            {
                // Anonymous call direct to SIP server specified in the URI.
                callURI    = SIPURI.ParseSIPURIRelaxed(destination);
                fromHeader = (new SIPFromHeader(m_sipFromName, SIPURI.ParseSIPURI(SIPFromHeader.DEFAULT_FROM_URI), null)).ToString();
            }
            else
            {
                // This call will use the pre-configured SIP account.
                callURI     = SIPURI.ParseSIPURIRelaxed(destination + "@" + m_sipServer);
                sipUsername = m_sipUsername;
                sipPassword = m_sipPassword;
                fromHeader  = (new SIPFromHeader(m_sipFromName, new SIPURI(m_sipFromName, m_sipServer, null), null)).ToString();
            }

            StatusMessage(this, $"Starting call to {callURI}.");

            var dstEndpoint = await SIPDns.ResolveAsync(callURI, false, _cts.Token);

            if (dstEndpoint == null)
            {
                StatusMessage(this, $"Call failed, could not resolve {callURI}.");
            }
            else
            {
                StatusMessage(this, $"Call progressing, resolved {callURI} to {dstEndpoint}.");
                System.Diagnostics.Debug.WriteLine($"DNS lookup result for {callURI}: {dstEndpoint}.");
                SIPCallDescriptor callDescriptor = new SIPCallDescriptor(sipUsername, sipPassword, callURI.ToString(), fromHeader, null, null, null, null, SIPCallDirection.Out, _sdpMimeContentType, null, null);
                callDescriptor.CallId = m_sipFromName;
                MediaSession          = CreateMediaSession();

                m_userAgent.RemotePutOnHold   += OnRemotePutOnHold;
                m_userAgent.RemoteTookOffHold += OnRemoteTookOffHold;
                Directory.CreateDirectory(SIPSoftPhoneState.OutputRecordingFolder);
                string guid = Guid.NewGuid().ToString();
                _waveFile = new WaveFileWriter(Path.Combine(SIPSoftPhoneState.OutputRecordingFolder, $"{guid}.mp3"), _waveFormat);
                await m_userAgent.InitiateCallAsync(callDescriptor, MediaSession);
            }
        }
Exemple #10
0
        /// <summary>
        /// Gets the call descriptor to allow an outgoing call to be placed.
        /// </summary>
        /// <param name="callUri">The URI to place the call to.</param>
        /// <param name="rtpSession">The RTP session that will be handling the RTP/RTCP packets for the call.</param>
        /// <returns>A call descriptor.</returns>
        private static SIPCallDescriptor GetCallDescriptor(string callUri)
        {
            // Create a call descriptor to place an outgoing call.
            SIPCallDescriptor callDescriptor = new SIPCallDescriptor(
                SIP_USERNAME,
                SIP_PASSWORD,
                callUri,
                $"sip:{SIP_USERNAME}@localhost",
                callUri,
                null, null, null,
                SIPCallDirection.Out,
                SDP.SDP_MIME_CONTENTTYPE,
                null,
                null);

            return(callDescriptor);
        }
Exemple #11
0
        public void CallWithAdjustedInviteHeaderTest()
        {
            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);
            SIPClientUserAgent userAgent = new SIPClientUserAgent(
                transport,
                new SIPEndPoint(new IPEndPoint(new IPAddress(new byte[] { 192, 168, 11, 50 }), 5060)),
                "owner",
                "admin",
                null);
            SIPContactHeader testHeader = new SIPContactHeader("Contact Name", new SIPURI("User", "Host", "Param=Value"));

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

            var desc = new SIPCallDescriptor(
                "user",
                "pass",
                "sip:user@host",
                "sip:user@host",
                "sip:destination@destinationhost",
                null,
                new List <string>(),
                "user",
                SIPCallDirection.Out,
                null,
                null,
                null);

            userAgent.Call(desc);

            channel.SIPMessageSent.WaitOne(5000);
            Assert.Contains(testHeader.ToString(), channel.LastSIPMessageSent);
        }
Exemple #12
0
        private void StartNewCallAsync(SIPCallDescriptor callDescriptor)
        {
            try
            {
                callDescriptor.DialPlanContextID = (m_dialPlanContext != null) ? m_dialPlanContext.DialPlanContextID : Guid.Empty;

                if (Thread.CurrentThread.Name == null)
                {
                    Thread.CurrentThread.Name = THEAD_NAME + DateTime.Now.ToString("HHmmss") + "-" + Crypto.GetRandomString(3);
                }

                StartNewCallSync(callDescriptor);
            }
            catch (Exception excp)
            {
                logger.Error("Exception StartNewCallAsync. " + excp.Message);
            }
        }
Exemple #13
0
        /// <summary>
        /// Places an outgoing SIP call.
        /// </summary>
        /// <param name="destination">The SIP URI to place a call to. The destination can be a full SIP URI in which case the all will
        /// be placed anonymously directly to that URI. Alternatively it can be just the user portion of a URI in which case it will
        /// be sent to the configured SIP server.</param>
        public void Call(MediaManager mediaManager, string destination)
        {
            //_initialisationTask.Wait(_cancelCallTokenSource.Token);

            _mediaManager = mediaManager;
            _mediaManager.NewCall();

            // Determine if this is a direct anonymous call or whether it should be placed using the pre-configured SIP server account.
            SIPURI callURI     = null;
            string sipUsername = null;
            string sipPassword = null;
            string fromHeader  = null;

            if (destination.Contains("@") || m_sipServer == null)
            {
                // Anonymous call direct to SIP server specified in the URI.
                callURI    = SIPURI.ParseSIPURIRelaxed(destination);
                fromHeader = (new SIPFromHeader(m_sipFromName, SIPURI.ParseSIPURI(SIPFromHeader.DEFAULT_FROM_URI), null)).ToString();
            }
            else
            {
                // This call will use the pre-configured SIP account.
                callURI     = SIPURI.ParseSIPURIRelaxed(destination + "@" + m_sipServer);
                sipUsername = m_sipUsername;
                sipPassword = m_sipPassword;
                fromHeader  = (new SIPFromHeader(m_sipFromName, new SIPURI(m_sipUsername, m_sipServer, null), null)).ToString();
            }

            StatusMessage("Starting call to " + callURI.ToString() + ".");

            m_uac               = new SIPClientUserAgent(m_sipTransport, null, null, null, null);
            m_uac.CallTrying   += CallTrying;
            m_uac.CallRinging  += CallRinging;
            m_uac.CallAnswered += CallAnswered;
            m_uac.CallFailed   += CallFailed;

            // Get the SDP requesting that the public IP address be used if the host on the call destination is not a private IP address.
            SDP sdp = _mediaManager.GetSDP(!(IPAddress.TryParse(callURI.Host, out _) && IPSocket.IsPrivateAddress(callURI.Host)));

            System.Diagnostics.Debug.WriteLine(sdp.ToString());
            SIPCallDescriptor callDescriptor = new SIPCallDescriptor(sipUsername, sipPassword, callURI.ToString(), fromHeader, null, null, null, null, SIPCallDirection.Out, _sdpMimeContentType, sdp.ToString(), null);

            m_uac.Call(callDescriptor);
        }
Exemple #14
0
        public void Call(SIPCallDescriptor descriptor)
        {
            try
            {
                CallDescriptor = descriptor;
                SIPURI destinationURI = SIPURI.ParseSIPURIRelaxed(descriptor.Uri);

                bool       wasSDPMangled = false;
                IPEndPoint sdpEndPoint   = null;
                if (descriptor.MangleIPAddress != null)
                {
                    sdpEndPoint = SDP.GetSDPRTPEndPoint(descriptor.Content);
                    if (sdpEndPoint != null)
                    {
                        descriptor.Content = SIPPacketMangler.MangleSDP(descriptor.Content, descriptor.MangleIPAddress.ToString(), out wasSDPMangled);
                    }
                }

                if (wasSDPMangled)
                {
                    Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "SDP on Google Voice call had RTP socket mangled from " + sdpEndPoint.ToString() + " to " + descriptor.MangleIPAddress.ToString() + ":" + sdpEndPoint.Port + ".", Owner));
                }
                else if (sdpEndPoint != null)
                {
                    Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "SDP on Google Voice call could not be mangled, using original RTP socket of " + sdpEndPoint.ToString() + ".", Owner));
                }

                SIPDialogue = m_googleVoiceCall.InitiateCall(descriptor.Username, descriptor.Password, descriptor.CallbackNumber, destinationURI.User, descriptor.CallbackPattern, descriptor.CallbackPhoneType, MAX_CALLBACK_WAIT_TIME, descriptor.ContentType, descriptor.Content);

                if (SIPDialogue != null)
                {
                    CallAnswered(this, null);
                }
                else
                {
                    CallFailed(this, "Google Voice call failed.");
                }
            }
            catch (Exception excp)
            {
                logger.Error("Exception GoogleVoiceCallAgent Call. " + excp.Message);
                CallFailed(this, excp.Message);
            }
        }
        /// <summary>
        /// Sends the SIP INVITE probe request.
        /// </summary>
        private void ProbeWorker(SIPAppServerWorker worker, bool isInitialProbe)
        {
            try
            {
                if (isInitialProbe)
                {
                    worker.InitialProbeCount++;
                }

                int               workerProcessID = worker.WorkerProcess.Id;
                SIPEndPoint       workerEndPoint  = worker.AppServerEndpoint;
                DateTime          probeSentAt     = DateTime.Now;
                SIPCallDescriptor callDescriptor  = new SIPCallDescriptor(m_dispatcherUsername, null, "sip:" + m_dispatcherUsername + "@" + workerEndPoint.GetIPEndPoint().ToString(),
                                                                          "sip:" + m_dispatcherUsername + "@sipcalldispatcher", "sip:" + workerEndPoint.GetIPEndPoint().ToString(), null, null, null, SIPCallDirection.Out, null, null, null);
                SIPClientUserAgent uac = new SIPClientUserAgent(m_sipTransport, null, null, null, null);

                uac.CallFailed += (failedUAC, errorMessage) =>
                {
                    AppServerCallFailed(failedUAC, errorMessage, workerProcessID, probeSentAt, isInitialProbe);
                };

                uac.CallAnswered += (call, sipResponse) =>
                {
                    if (sipResponse.Status != SIPResponseStatusCodesEnum.BadExtension)
                    {
                        //logger.Warn("Probe call answered with unexpected response code of " + sipResponse.StatusCode + ".");
                        AppServerCallFailed(call, "Unexpected response of " + ((int)sipResponse.StatusCode) + " on probe call.", workerProcessID, probeSentAt, isInitialProbe);
                    }
                    else
                    {
                        AppServerCallSucceeded(call);
                    }
                };

                uac.Call(callDescriptor);
            }
            catch (Exception excp)
            {
                logger.Error("Exception SIPAppServerManager ProberWorker. " + excp.Message);
            }
        }
Exemple #16
0
        /// <summary>
        /// Places an outgoing SIP call.
        /// </summary>
        /// <param name="destination">The SIP URI to place a call to. The destination can be a full SIP URI in which case the all will
        /// be placed anonymously directly to that URI. Alternatively it can be just the user portion of a URI in which case it will
        /// be sent to the configured SIP server.</param>
        public void Call(string destination)
        {
            // Determine if this is a direct anonymous call or whether it should be placed using the pre-configured SIP server account.
            SIPURI callURI     = null;
            string sipUsername = null;
            string sipPassword = null;
            string fromHeader  = null;

            if (destination.Contains("@") || m_sipServer == null)
            {
                // Anonymous call direct to SIP server specified in the URI.
                callURI = SIPURI.ParseSIPURIRelaxed(destination);
            }
            else
            {
                // This call will use the pre-configured SIP account.
                callURI     = SIPURI.ParseSIPURIRelaxed(destination + "@" + m_sipServer);
                sipUsername = m_sipUsername;
                sipPassword = m_sipPassword;
                fromHeader  = (new SIPFromHeader(m_sipFromName, new SIPURI(m_sipUsername, m_sipServer, null), null)).ToString();
            }

            StatusMessage("Starting call to " + callURI.ToString() + ".");

            m_uac               = new SIPClientUserAgent(m_sipTransport, null, null, null, null);
            m_uac.CallTrying   += CallTrying;
            m_uac.CallRinging  += CallRinging;
            m_uac.CallAnswered += CallAnswered;
            m_uac.CallFailed   += CallFailed;

            _audioChannel = new AudioChannel();

            // Get the SDP requesting that the public IP address be used if the host on the call destination is not a private IP address.
            SDP sdp = _audioChannel.GetSDP(!(IPSocket.IsIPAddress(callURI.Host) && IPSocket.IsPrivateAddress(callURI.Host)));
            SIPCallDescriptor callDescriptor = new SIPCallDescriptor(sipUsername, sipPassword, callURI.ToString(), fromHeader, null, null, null, null, SIPCallDirection.Out, SDP.SDP_MIME_CONTENTTYPE, sdp.ToString(), null);

            m_uac.Call(callDescriptor);
        }
Exemple #17
0
        private static int INPUT_SAMPLE_PERIOD_MILLISECONDS = 20;            // This sets the frequency of the RTP packets.

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

            // Plumbing code to facilitate a graceful exit.
            ManualResetEvent exitMre       = new ManualResetEvent(false);
            bool             isCallHungup  = false;
            bool             hasCallFailed = false;

            AddConsoleLogger();

            SIPURI callUri = SIPURI.ParseSIPURI(DEFAULT_DESTINATION_SIP_URI);

            if (args != null && args.Length > 0)
            {
                if (!SIPURI.TryParse(args[0], out callUri))
                {
                    Log.LogWarning($"Command line argument could not be parsed as a SIP URI {args[0]}");
                }
            }
            Log.LogInformation($"Call destination {callUri}.");

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

            EnableTraceLogs(sipTransport);

            // Get the IP address the RTP will be sent from. While we can listen on IPAddress.Any | IPv6Any
            // we can't put 0.0.0.0 or [::0] in the SDP or the callee will ignore us.
            var lookupResult = SIPDNSManager.ResolveSIPService(callUri, false);

            Log.LogDebug($"DNS lookup result for {callUri}: {lookupResult?.GetSIPEndPoint()}.");
            var       dstAddress     = lookupResult.GetSIPEndPoint().Address;
            IPAddress localIPAddress = NetServices.GetLocalAddressForRemote(dstAddress);

            // Initialise an RTP session to receive the RTP packets from the remote SIP server.
            var rtpSession = new RTPMediaSession((int)SDPMediaFormatsEnum.PCMU, localIPAddress.AddressFamily);
            var offerSDP   = rtpSession.GetSDP(localIPAddress);

            // Get the audio input device.
            WaveInEvent waveInEvent = GetAudioInputDevice();

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

            uac.CallTrying  += (uac, resp) => Log.LogInformation($"{uac.CallDescriptor.To} Trying: {resp.StatusCode} {resp.ReasonPhrase}.");
            uac.CallRinging += (uac, resp) => Log.LogInformation($"{uac.CallDescriptor.To} Ringing: {resp.StatusCode} {resp.ReasonPhrase}.");
            uac.CallFailed  += (uac, err) =>
            {
                Log.LogWarning($"{uac.CallDescriptor.To} Failed: {err}");
                hasCallFailed = true;
            };
            uac.CallAnswered += (uac, resp) =>
            {
                if (resp.Status == SIPResponseStatusCodesEnum.Ok)
                {
                    Log.LogInformation($"{uac.CallDescriptor.To} Answered: {resp.StatusCode} {resp.ReasonPhrase}.");

                    // Only set the remote RTP end point if there hasn't already been a packet received on it.
                    if (rtpSession.DestinationEndPoint == null)
                    {
                        rtpSession.DestinationEndPoint = SDP.GetSDPRTPEndPoint(resp.Body);
                        Log.LogDebug($"Remote RTP socket {rtpSession.DestinationEndPoint}.");
                    }

                    rtpSession.SetRemoteSDP(SDP.ParseSDPDescription(resp.Body));
                    waveInEvent.StartRecording();
                }
                else
                {
                    Log.LogWarning($"{uac.CallDescriptor.To} Answered: {resp.StatusCode} {resp.ReasonPhrase}.");
                }
            };

            // The only incoming request that needs to be explicitly handled for this example is if the remote end hangs up the call.
            sipTransport.SIPTransportRequestReceived += async(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPRequest sipRequest) =>
            {
                if (sipRequest.Method == SIPMethodsEnum.BYE)
                {
                    SIPResponse okResponse = SIPResponse.GetResponse(sipRequest, SIPResponseStatusCodesEnum.Ok, null);
                    await sipTransport.SendResponseAsync(okResponse);

                    if (uac.IsUACAnswered)
                    {
                        Log.LogInformation("Call was hungup by remote server.");
                        isCallHungup = true;
                        exitMre.Set();
                    }
                }
            };

            // Wire up the RTP receive session to the audio output device.
            var(audioOutEvent, audioOutProvider) = GetAudioOutputDevice();
            rtpSession.OnReceivedSampleReady    += (sample) =>
            {
                for (int index = 0; index < sample.Length; index++)
                {
                    short  pcm       = NAudio.Codecs.MuLawDecoder.MuLawToLinearSample(sample[index]);
                    byte[] pcmSample = new byte[] { (byte)(pcm & 0xFF), (byte)(pcm >> 8) };
                    audioOutProvider.AddSamples(pcmSample, 0, 2);
                }
            };

            // Wire up the RTP send session to the audio input 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 (rtpSession.DestinationEndPoint != null)
                {
                    rtpSession.SendAudioFrame(rtpSendTimestamp, sample);
                    rtpSendTimestamp += (uint)(8000 / waveInEvent.BufferMilliseconds);
                }
            };

            // Start the thread that places the call.
            SIPCallDescriptor callDescriptor = new SIPCallDescriptor(
                SIPConstants.SIP_DEFAULT_USERNAME,
                null,
                callUri.ToString(),
                SIPConstants.SIP_DEFAULT_FROMURI,
                callUri.CanonicalAddress,
                null, null, null,
                SIPCallDirection.Out,
                SDP.SDP_MIME_CONTENTTYPE,
                offerSDP.ToString(),
                null);

            uac.Call(callDescriptor);
            uac.ServerTransaction.TransactionTraceMessage += (tx, msg) => Log.LogInformation($"UAC tx trace message. {msg}");

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

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

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

            waveInEvent?.StopRecording();
            audioOutEvent?.Stop();
            rtpSession.CloseSession(null);

            if (!isCallHungup && uac != null)
            {
                if (uac.IsUACAnswered)
                {
                    Log.LogInformation($"Hanging up call to {uac.CallDescriptor.To}.");
                    uac.Hangup();
                }
                else if (!hasCallFailed)
                {
                    Log.LogInformation($"Cancelling call to {uac.CallDescriptor.To}.");
                    uac.Cancel();
                }

                // Give the BYE or CANCEL request time to be transmitted.
                Log.LogInformation("Waiting 1s for call to clean up...");
                Task.Delay(1000).Wait();
            }

            SIPSorcery.Net.DNSManager.Stop();

            if (sipTransport != null)
            {
                Log.LogInformation("Shutting down SIP transport...");
                sipTransport.Shutdown();
            }
        }
Exemple #18
0
        static void Main()
        {
            Console.WriteLine("SIPSorcery client user agent example.");
            Console.WriteLine("Press ctrl-c to exit.");

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

            AddConsoleLogger();

            SIPURI callUri = SIPURI.ParseSIPURI(DEFAULT_DESTINATION_SIP_URI);

            Log.LogInformation($"Call destination {callUri}.");

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

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

            // Un/comment this line to see/hide each SIP message sent and received.
            EnableTraceLogs(sipTransport);

            // Note this relies on the callURI host being an IP address. If it's a hostname a DNS lookup is required.
            IPAddress localIPAddress = NetServices.GetLocalAddressForRemote(callUri.ToSIPEndPoint().Address);

            // Initialise an RTP session to receive the RTP packets from the remote SIP server.
            var rtpSession = new RTPSession((int)SDPMediaFormatsEnum.PCMU, null, null, true, localIPAddress.AddressFamily);
            var offerSDP   = rtpSession.GetSDP(localIPAddress);

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

            uac.CallTrying += (uac, resp) =>
            {
                Log.LogInformation($"{uac.CallDescriptor.To} Trying: {resp.StatusCode} {resp.ReasonPhrase}.");
            };
            uac.CallRinging += (uac, resp) => Log.LogInformation($"{uac.CallDescriptor.To} Ringing: {resp.StatusCode} {resp.ReasonPhrase}.");
            uac.CallFailed  += (uac, err) =>
            {
                Log.LogWarning($"{uac.CallDescriptor.To} Failed: {err}");
                hasCallFailed = true;
            };
            uac.CallAnswered += (uac, resp) =>
            {
                if (resp.Status == SIPResponseStatusCodesEnum.Ok)
                {
                    Log.LogInformation($"{uac.CallDescriptor.To} Answered: {resp.StatusCode} {resp.ReasonPhrase}.");
                    rtpSession.DestinationEndPoint = SDP.GetSDPRTPEndPoint(resp.Body);
                    Log.LogDebug($"Remote RTP socket {rtpSession.DestinationEndPoint}.");
                }
                else
                {
                    Log.LogWarning($"{uac.CallDescriptor.To} Answered: {resp.StatusCode} {resp.ReasonPhrase}.");
                }
            };

            // The only incoming request that needs to be explicitly handled for this example is if the remote end hangs up the call.
            sipTransport.SIPTransportRequestReceived += async(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPRequest sipRequest) =>
            {
                if (sipRequest.Method == SIPMethodsEnum.BYE)
                {
                    SIPResponse okResponse = SIPResponse.GetResponse(sipRequest, SIPResponseStatusCodesEnum.Ok, null);
                    await sipTransport.SendResponseAsync(okResponse);

                    if (uac.IsUACAnswered)
                    {
                        Log.LogInformation("Call was hungup by remote server.");
                        isCallHungup = true;
                        rtpCts.Cancel();
                    }
                }
            };

            // Wire up the RTP receive session to the default speaker.
            var(audioOutEvent, audioOutProvider) = GetAudioOutputDevice();
            rtpSession.OnReceivedSampleReady    += (sample) =>
            {
                for (int index = 0; index < sample.Length; index++)
                {
                    short  pcm       = NAudio.Codecs.MuLawDecoder.MuLawToLinearSample(sample[index]);
                    byte[] pcmSample = new byte[] { (byte)(pcm & 0xFF), (byte)(pcm >> 8) };
                    audioOutProvider.AddSamples(pcmSample, 0, 2);
                }
            };

            // Send audio packets (in this case silence) to the callee.
            Task.Run(() => SendSilence(rtpSession, rtpCts));

            // Start the thread that places the call.
            SIPCallDescriptor callDescriptor = new SIPCallDescriptor(
                SIPConstants.SIP_DEFAULT_USERNAME,
                null,
                callUri.ToString(),
                SIPConstants.SIP_DEFAULT_FROMURI,
                null, null, null, null,
                SIPCallDirection.Out,
                SDP.SDP_MIME_CONTENTTYPE,
                offerSDP.ToString(),
                null);

            uac.Call(callDescriptor);

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

            // Give the call some time to answer.
            Task.Delay(3000).Wait();

            // Send some DTMF key presses via RTP events.
            var dtmf5 = new RTPEvent(0x05, false, RTPEvent.DEFAULT_VOLUME, 1200, RTPSession.DTMF_EVENT_PAYLOAD_ID);

            rtpSession.SendDtmfEvent(dtmf5, rtpCts.Token).Wait();
            Task.Delay(2000, rtpCts.Token).Wait();

            var dtmf9 = new RTPEvent(0x09, false, RTPEvent.DEFAULT_VOLUME, 1200, RTPSession.DTMF_EVENT_PAYLOAD_ID);

            rtpSession.SendDtmfEvent(dtmf9, rtpCts.Token).Wait();
            Task.Delay(2000, rtpCts.Token).Wait();

            var dtmf2 = new RTPEvent(0x02, false, RTPEvent.DEFAULT_VOLUME, 1200, RTPSession.DTMF_EVENT_PAYLOAD_ID);

            rtpSession.SendDtmfEvent(dtmf2, rtpCts.Token).Wait();
            Task.Delay(2000, rtpCts.Token).ContinueWith((task) => { }).Wait(); // Don't care about the exception if the cancellation token is set.

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

            rtpCts.Cancel();
            audioOutEvent?.Stop();
            rtpSession.CloseSession(null);

            if (!isCallHungup && uac != null)
            {
                if (uac.IsUACAnswered)
                {
                    Log.LogInformation($"Hanging up call to {uac.CallDescriptor.To}.");
                    uac.Hangup();
                }
                else if (!hasCallFailed)
                {
                    Log.LogInformation($"Cancelling call to {uac.CallDescriptor.To}.");
                    uac.Cancel();
                }

                // Give the BYE or CANCEL request time to be transmitted.
                Log.LogInformation("Waiting 1s for call to clean up...");
                Task.Delay(1000).Wait();
            }

            SIPSorcery.Net.DNSManager.Stop();

            if (sipTransport != null)
            {
                Log.LogInformation("Shutting down SIP transport...");
                sipTransport.Shutdown();
            }
        }
Exemple #19
0
        static void Main(string[] args)
        {
            Console.WriteLine("SIPSorcery client user agent example.");
            Console.WriteLine("Press ctrl-c to exit.");

            // Plumbing code to facilitate a graceful exit.
            ManualResetEvent exitMre       = new ManualResetEvent(false);
            bool             isCallHungup  = false;
            bool             hasCallFailed = false;

            Log = AddConsoleLogger();

            SIPURI callUri = SIPURI.ParseSIPURI(DEFAULT_DESTINATION_SIP_URI);

            if (args != null && args.Length > 0)
            {
                if (!SIPURI.TryParse(args[0], out callUri))
                {
                    Log.LogWarning($"Command line argument could not be parsed as a SIP URI {args[0]}");
                }
            }
            Log.LogInformation($"Call destination {callUri}.");

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

            EnableTraceLogs(sipTransport);

            var audioSession = new WindowsAudioEndPoint(new AudioEncoder());
            var rtpSession   = new VoIPMediaSession(audioSession.ToMediaEndPoints());

            var offerSDP = rtpSession.CreateOffer(null);

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

            uac.CallTrying  += (uac, resp) => Log.LogInformation($"{uac.CallDescriptor.To} Trying: {resp.StatusCode} {resp.ReasonPhrase}.");
            uac.CallRinging += async(uac, resp) =>
            {
                Log.LogInformation($"{uac.CallDescriptor.To} Ringing: {resp.StatusCode} {resp.ReasonPhrase}.");
                if (resp.Status == SIPResponseStatusCodesEnum.SessionProgress)
                {
                    await rtpSession.Start();
                }
            };
            uac.CallFailed += (uac, err, resp) =>
            {
                Log.LogWarning($"Call attempt to {uac.CallDescriptor.To} Failed: {err}");
                hasCallFailed = true;
            };
            uac.CallAnswered += async(iuac, resp) =>
            {
                if (resp.Status == SIPResponseStatusCodesEnum.Ok)
                {
                    Log.LogInformation($"{uac.CallDescriptor.To} Answered: {resp.StatusCode} {resp.ReasonPhrase}.");

                    var result = rtpSession.SetRemoteDescription(SdpType.answer, SDP.ParseSDPDescription(resp.Body));
                    if (result == SetDescriptionResultEnum.OK)
                    {
                        await rtpSession.Start();
                    }
                    else
                    {
                        Log.LogWarning($"Failed to set remote description {result}.");
                        uac.Hangup();
                    }
                }
                else
                {
                    Log.LogWarning($"{uac.CallDescriptor.To} Answered: {resp.StatusCode} {resp.ReasonPhrase}.");
                }
            };

            // The only incoming request that needs to be explicitly handled for this example is if the remote end hangs up the call.
            sipTransport.SIPTransportRequestReceived += async(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPRequest sipRequest) =>
            {
                if (sipRequest.Method == SIPMethodsEnum.BYE)
                {
                    SIPResponse okResponse = SIPResponse.GetResponse(sipRequest, SIPResponseStatusCodesEnum.Ok, null);
                    await sipTransport.SendResponseAsync(okResponse);

                    if (uac.IsUACAnswered)
                    {
                        Log.LogInformation("Call was hungup by remote server.");
                        isCallHungup = true;
                        exitMre.Set();
                    }
                }
            };

            // Start the thread that places the call.
            SIPCallDescriptor callDescriptor = new SIPCallDescriptor(
                SIPConstants.SIP_DEFAULT_USERNAME,
                null,
                callUri.ToString(),
                SIPConstants.SIP_DEFAULT_FROMURI,
                callUri.CanonicalAddress,
                null, null, null,
                SIPCallDirection.Out,
                SDP.SDP_MIME_CONTENTTYPE,
                offerSDP.ToString(),
                null);

            uac.Call(callDescriptor, null);
            uac.ServerTransaction.TransactionTraceMessage += (tx, msg) => Log.LogInformation($"UAC tx trace message. {msg}");

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

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

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

            rtpSession.Close(null);

            if (!isCallHungup && uac != null)
            {
                if (uac.IsUACAnswered)
                {
                    Log.LogInformation($"Hanging up call to {uac.CallDescriptor.To}.");
                    uac.Hangup();
                }
                else if (!hasCallFailed)
                {
                    Log.LogInformation($"Cancelling call to {uac.CallDescriptor.To}.");
                    uac.Cancel();
                }

                // Give the BYE or CANCEL request time to be transmitted.
                Log.LogInformation("Waiting 1s for call to clean up...");
                Task.Delay(1000).Wait();
            }

            if (sipTransport != null)
            {
                Log.LogInformation("Shutting down SIP transport...");
                sipTransport.Shutdown();
            }
        }
Exemple #20
0
        /// <summary>
        /// Establishes a new call with the client end tied to the proxy. Since the proxy will not be sending any audio the idea is that once
        /// the call is up it should be re-INVITED off somewhere else pronto to avoid the callee sitting their listening to dead air.
        /// </summary>
        /// <param name="dest1">The dial string of the first call to place.</param>
        /// <param name="dest2">The dial string of the second call to place.</param>
        /// <param name="delaySeconds">Delay in seconds before placing the first call. Gives the user a chance to hangup their phone if they are calling themselves back.</param>
        /// <param name="ringTimeoutLeg1">The ring timeout for the first call leg, If 0 the max timeout will be used.</param>
        /// <param name="ringTimeoutLeg1">The ring timeout for the second call leg, If 0 the max timeout will be used.</param>
        /// <param name="customHeadersCallLeg1">A | delimited string that contains a list of custom SIP headers to add to the INVITE request sent for the first call leg.</param>
        /// /// <param name="customHeadersCallLeg2">A | delimited string that contains a list of custom SIP headers to add to the INVITE request sent for the second call leg.</param>
        /// <returns>The result of the call.</returns>
        public void Callback(string dest1, string dest2, int delaySeconds, int ringTimeoutLeg1, int ringTimeoutLeg2, string customHeadersCallLeg1, string customHeadersCallLeg2)
        {
            var ts = new CancellationTokenSource();
            CancellationToken ct = ts.Token;

            try
            {
                if (delaySeconds > 0)
                {
                    delaySeconds = (delaySeconds > MAXCALLBACK_DELAY_SECONDS) ? MAXCALLBACK_DELAY_SECONDS : delaySeconds;
                    Log("Callback app delaying by " + delaySeconds + "s.");
                    Thread.Sleep(delaySeconds * 1000);
                }

                Log("Callback app commencing first leg to " + dest1 + ".");

                SIPEndPoint defaultUDPEP = m_sipTransport.GetDefaultSIPEndPoint(SIPProtocolsEnum.udp);

                SIPRequest firstLegDummyInviteRequest = GetCallbackInviteRequest(defaultUDPEP.GetIPEndPoint(), null);
                ForkCall   firstLegCall = new ForkCall(m_sipTransport, Log_External, m_callManager.QueueNewCall, null, m_username, m_adminMemberId, m_outboundProxy, m_callManager, null);
                m_firstLegDialogue = Dial(firstLegCall, dest1, ringTimeoutLeg1, 0, firstLegDummyInviteRequest, SIPCallDescriptor.ParseCustomHeaders(customHeadersCallLeg1));
                if (m_firstLegDialogue == null)
                {
                    Log("The first call leg to " + dest1 + " was unsuccessful.");
                    return;
                }

                // Persist the dialogue to the database so any hangup can be detected.
                m_sipDialoguePersistor.Add(new SIPDialogueAsset(m_firstLegDialogue));

                SDP    firstLegSDP       = SDP.ParseSDPDescription(m_firstLegDialogue.RemoteSDP);
                string call1SDPIPAddress = firstLegSDP.Connection.ConnectionAddress;
                int    call1SDPPort      = firstLegSDP.Media[0].Port;
                Log("The first call leg to " + dest1 + " was successful, audio socket=" + call1SDPIPAddress + ":" + call1SDPPort + ".");

                Log("Callback app commencing second leg to " + dest2 + ".");

                SIPRequest secondLegDummyInviteRequest = GetCallbackInviteRequest(defaultUDPEP.GetIPEndPoint(), m_firstLegDialogue.RemoteSDP);
                ForkCall   secondLegCall = new ForkCall(m_sipTransport, Log_External, m_callManager.QueueNewCall, null, m_username, m_adminMemberId, m_outboundProxy, m_callManager, null);

                Task.Factory.StartNew(() =>
                {
                    while (true)
                    {
                        Thread.Sleep(CHECK_FIRST_LEG_FOR_HANGUP_PERIOD);

                        Console.WriteLine("Checking if first call leg is still up...");

                        if (ct.IsCancellationRequested)
                        {
                            Console.WriteLine("Checking first call leg task was cancelled.");
                            break;
                        }
                        else
                        {
                            // Check that the first call leg hasn't been hung up.
                            var dialog = m_sipDialoguePersistor.Get(m_firstLegDialogue.Id);
                            if (dialog == null)
                            {
                                Console.WriteLine("First call leg has been hungup.");

                                // The first call leg has been hungup while waiting for the second call.
                                Log("The first call leg was hungup while the second call leg was waiting for an answer.");
                                secondLegCall.CancelNotRequiredCallLegs(CallCancelCause.ClientCancelled);
                                break;
                            }
                        }
                    }

                    Console.WriteLine("Checking first call leg task finished...");
                }, ct);

                SIPDialogue secondLegDialogue = Dial(secondLegCall, dest2, ringTimeoutLeg2, 0, secondLegDummyInviteRequest, SIPCallDescriptor.ParseCustomHeaders(customHeadersCallLeg2));

                ts.Cancel();

                if (secondLegDialogue == null)
                {
                    Log("The second call leg to " + dest2 + " was unsuccessful.");
                    m_firstLegDialogue.Hangup(m_sipTransport, m_outboundProxy);
                    return;
                }

                // Check that the first call leg hasn't been hung up.
                var firstLegDialog = m_sipDialoguePersistor.Get(m_firstLegDialogue.Id);
                if (firstLegDialog == null)
                {
                    // The first call leg has been hungup while waiting for the second call.
                    Log("The first call leg was hungup while waiting for the second call leg.");
                    secondLegDialogue.Hangup(m_sipTransport, m_outboundProxy);
                    return;
                }

                SDP    secondLegSDP      = SDP.ParseSDPDescription(secondLegDialogue.RemoteSDP);
                string call2SDPIPAddress = secondLegSDP.Connection.ConnectionAddress;
                int    call2SDPPort      = secondLegSDP.Media[0].Port;
                Log("The second call leg to " + dest2 + " was successful, audio socket=" + call2SDPIPAddress + ":" + call2SDPPort + ".");

                // Persist the second leg dialogue and update the bridge ID on the first call leg.
                Guid bridgeId = Guid.NewGuid();
                secondLegDialogue.BridgeId = bridgeId;
                m_sipDialoguePersistor.Add(new SIPDialogueAsset(secondLegDialogue));
                m_sipDialoguePersistor.UpdateProperty(firstLegDialog.Id, "BridgeID", bridgeId.ToString());

                //m_callManager.CreateDialogueBridge(m_firstLegDialogue, secondLegDialogue, m_username);

                Log("Re-inviting Callback dialogues to each other.");

                m_callManager.ReInvite(m_firstLegDialogue, secondLegDialogue);
                //m_callManager.ReInvite(secondLegDialogue, m_firstLegDialogue.RemoteSDP);

                SendRTPPacket(call2SDPIPAddress + ":" + call2SDPPort, call1SDPIPAddress + ":" + call1SDPPort);
                SendRTPPacket(call1SDPIPAddress + ":" + call1SDPPort, call2SDPIPAddress + ":" + call2SDPPort);
            }
            catch (Exception excp)
            {
                logger.Error("Exception CallbackApp. " + excp);
                Log("Exception in Callback. " + excp);
            }
            finally
            {
                if (!ts.IsCancellationRequested)
                {
                    ts.Cancel();
                }
            }
        }
Exemple #21
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;

            AddConsoleLogger();

            // Check whether an override desination has been entered on the command line.
            SIPURI callUri = SIPURI.ParseSIPURI(DEFAULT_DESTINATION_SIP_URI);

            if (args != null && args.Length > 0)
            {
                if (!SIPURI.TryParse(args[0]))
                {
                    Log.LogWarning($"Command line argument could not be parsed as a SIP URI {args[0]}");
                }
                else
                {
                    callUri = SIPURI.ParseSIPURIRelaxed(args[0]);
                }
            }
            Log.LogInformation($"Call destination {callUri}.");

            // Set up a default SIP transport.
            _sipTransport = new SIPTransport();
            _sipTransport.AddSIPChannel(new SIPUDPChannel(new IPEndPoint(IPAddress.Any, 0)));

            EnableTraceLogs(_sipTransport);

            var lookupResult = SIPDNSManager.ResolveSIPService(callUri, false);

            Log.LogDebug($"DNS lookup result for {callUri}: {lookupResult?.GetSIPEndPoint()}.");
            var dstAddress = lookupResult.GetSIPEndPoint().Address;

            IPAddress localIPAddress = NetServices.GetLocalAddressForRemote(dstAddress);

            // Initialise an RTP session to receive the RTP packets from the remote SIP server.
            _ourRtpSocket = null;
            Socket controlSocket = null;

            NetServices.CreateRtpSocket(localIPAddress, 48000, 48100, false, out _ourRtpSocket, out controlSocket);
            var rtpRecvSession = new RTPSession((int)RTPPayloadTypesEnum.PCMU, null, null);
            var rtpSendSession = new RTPSession((int)RTPPayloadTypesEnum.PCMU, null, null);

            _ourSDP = GetSDP(_ourRtpSocket.LocalEndPoint as IPEndPoint, RTP_ATTRIBUTE_SENDRECV);

            // 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}.");

                    // Only set the remote RTP end point if there hasn't already been a packet received on it.
                    if (_remoteRtpEndPoint == null)
                    {
                        _remoteRtpEndPoint = SDP.GetSDPRTPEndPoint(resp.Body);
                        Log.LogDebug($"Remote RTP socket {_remoteRtpEndPoint}.");
                    }
                }
                else
                {
                    Log.LogWarning($"{uac.CallDescriptor.To} Answered: {resp.StatusCode} {resp.ReasonPhrase}.");
                }
            };
            userAgent.CallHungup += () =>
            {
                Log.LogInformation($"Call hungup by remote party.");
                exitCts.Cancel();
            };
            userAgent.OnReinviteRequest += ReinviteRequestReceived;

            // The only incoming requests that need to be explicitly in this example program are in-dialog
            // re-INVITE requests that are being used to place the call on/off hold.
            _sipTransport.SIPTransportRequestReceived += (localSIPEndPoint, remoteEndPoint, sipRequest) =>
            {
                try
                {
                    if (sipRequest.Header.From != null &&
                        sipRequest.Header.From.FromTag != null &&
                        sipRequest.Header.To != null &&
                        sipRequest.Header.To.ToTag != null)
                    {
                        userAgent.InDialogRequestReceivedAsync(sipRequest).Wait();
                    }
                    else if (sipRequest.Method == SIPMethodsEnum.OPTIONS)
                    {
                        SIPResponse optionsResponse = SIPTransport.GetResponse(sipRequest, SIPResponseStatusCodesEnum.Ok, null);
                        _sipTransport.SendResponse(optionsResponse);
                    }
                }
                catch (Exception excp)
                {
                    Log.LogError($"Exception processing request. {excp.Message}");
                }
            };

            // It's a good idea to start the RTP receiving socket before the call request is sent.
            // A SIP server will generally start sending RTP as soon as it has processed the incoming call request and
            // being ready to receive will stop any ICMP error response being generated.
            Task.Run(() => RecvRtp(_ourRtpSocket, rtpRecvSession, exitCts));
            Task.Run(() => SendRtp(_ourRtpSocket, rtpSendSession, exitCts));

            // Start the thread that places the call.
            SIPCallDescriptor callDescriptor = new SIPCallDescriptor(
                SIP_USERNAME,
                SIP_PASSWORD,
                callUri.ToString(),
                $"sip:{SIP_USERNAME}@localhost",
                callUri.CanonicalAddress,
                null, null, null,
                SIPCallDirection.Out,
                SDP.SDP_MIME_CONTENTTYPE,
                _ourSDP.ToString(),
                null);

            userAgent.Call(callDescriptor);

            // At this point the call has been initiated and everything will be handled in an event handler.
            Task.Run(() =>
            {
                try
                {
                    while (!exitCts.Token.WaitHandle.WaitOne(0))
                    {
                        var keyProps = Console.ReadKey();
                        if (keyProps.KeyChar == 'h')
                        {
                            // Place call on/off hold.
                            if (userAgent.IsAnswered)
                            {
                                if (_holdStatus == HoldStatus.None)
                                {
                                    Log.LogInformation("Placing the remote call party on hold.");
                                    _holdStatus = HoldStatus.WePutOnHold;
                                    _ourSDP     = GetSDP(_ourRtpSocket.LocalEndPoint as IPEndPoint, RTP_ATTRIBUTE_SENDONLY);
                                    userAgent.SendReInviteRequest(_ourSDP);
                                }
                                else if (_holdStatus == HoldStatus.WePutOnHold)
                                {
                                    Log.LogInformation("Removing the remote call party from hold.");
                                    _holdStatus = HoldStatus.None;
                                    _ourSDP     = GetSDP(_ourRtpSocket.LocalEndPoint as IPEndPoint, RTP_ATTRIBUTE_SENDRECV);
                                    userAgent.SendReInviteRequest(_ourSDP);
                                }
                                else
                                {
                                    Log.LogInformation("Sorry we're already on hold by the remote call party.");
                                }
                            }
                        }
                        else if (keyProps.KeyChar == 'q')
                        {
                            // Quit application.
                            exitCts.Cancel();
                        }
                    }
                }
                catch (Exception excp)
                {
                    SIPSorcery.Sys.Log.Logger.LogError($"Exception Key Press listener. {excp.Message}.");
                }
            });

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

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

            #region Cleanup.

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

            _ourRtpSocket?.Close();
            controlSocket?.Close();

            if (!isCallHungup && userAgent != null)
            {
                if (userAgent.IsAnswered)
                {
                    Log.LogInformation($"Hanging up call to {userAgent?.CallDescriptor?.To}.");
                    userAgent.Hangup();
                }
                else if (!hasCallFailed)
                {
                    Log.LogInformation($"Cancelling call to {userAgent?.CallDescriptor?.To}.");
                    userAgent.Cancel();
                }

                // Give the BYE or CANCEL request time to be transmitted.
                Log.LogInformation("Waiting 1s for call to clean up...");
                Task.Delay(1000).Wait();
            }

            SIPSorcery.Net.DNSManager.Stop();

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

            #endregion
        }
Exemple #22
0
        private static ConcurrentQueue <RTPEvent> _dtmfEvents = new ConcurrentQueue <RTPEvent>(); // Add a DTMF event to this queue to have the it sent

        static void Main()
        {
            Console.WriteLine("SIPSorcery client user agent example.");
            Console.WriteLine("Press ctrl-c to exit.");

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

            AddConsoleLogger();

            SIPURI callUri = SIPURI.ParseSIPURI(DEFAULT_DESTINATION_SIP_URI);

            Log.LogInformation($"Call destination {callUri}.");

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

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

            // Un/comment this line to see/hide each SIP message sent and received.
            EnableTraceLogs(sipTransport);

            // Note this relies on the callURI host being an IP address. If it's a hostname a DNS lookup is required.
            IPAddress localIPAddress = NetServices.GetLocalAddressForRemote(callUri.ToSIPEndPoint().Address);

            // Initialise an RTP session to receive the RTP packets from the remote SIP server.
            Socket rtpSocket     = null;
            Socket controlSocket = null;

            NetServices.CreateRtpSocket(localIPAddress, 49000, 49100, false, out rtpSocket, out controlSocket);
            var rtpRecvSession = new RTPSession((int)RTPPayloadTypesEnum.PCMU, null, null);
            var rtpSendSession = new RTPSession((int)RTPPayloadTypesEnum.PCMU, null, null);

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

            uac.CallTrying += (uac, resp) =>
            {
                Log.LogInformation($"{uac.CallDescriptor.To} Trying: {resp.StatusCode} {resp.ReasonPhrase}.");
            };
            uac.CallRinging += (uac, resp) => Log.LogInformation($"{uac.CallDescriptor.To} Ringing: {resp.StatusCode} {resp.ReasonPhrase}.");
            uac.CallFailed  += (uac, err) =>
            {
                Log.LogWarning($"{uac.CallDescriptor.To} Failed: {err}");
                hasCallFailed = true;
            };
            uac.CallAnswered += (uac, resp) =>
            {
                if (resp.Status == SIPResponseStatusCodesEnum.Ok)
                {
                    Log.LogInformation($"{uac.CallDescriptor.To} Answered: {resp.StatusCode} {resp.ReasonPhrase}.");

                    _remoteRtpEndPoint = SDP.GetSDPRTPEndPoint(resp.Body);

                    Log.LogDebug($"Remote RTP socket {_remoteRtpEndPoint}.");
                }
                else
                {
                    Log.LogWarning($"{uac.CallDescriptor.To} Answered: {resp.StatusCode} {resp.ReasonPhrase}.");
                }
            };

            // The only incoming request that needs to be explicitly handled for this example is if the remote end hangs up the call.
            sipTransport.SIPTransportRequestReceived += (SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPRequest sipRequest) =>
            {
                if (sipRequest.Method == SIPMethodsEnum.BYE)
                {
                    SIPNonInviteTransaction byeTransaction = sipTransport.CreateNonInviteTransaction(sipRequest, null);
                    SIPResponse             byeResponse    = SIPTransport.GetResponse(sipRequest, SIPResponseStatusCodesEnum.Ok, null);
                    byeTransaction.SendFinalResponse(byeResponse);

                    if (uac.IsUACAnswered)
                    {
                        Log.LogInformation("Call was hungup by remote server.");
                        isCallHungup = true;
                        rtpCts.Cancel();
                    }
                }
            };

            // It's a good idea to start the RTP receiving socket before the call request is sent.
            // A SIP server will generally start sending RTP as soon as it has processed the incoming call request and
            // being ready to receive will stop any ICMP error response being generated.
            Task.Run(() => RecvRtp(rtpSocket, rtpRecvSession, rtpCts));
            Task.Run(() => SendRtp(rtpSocket, rtpSendSession, rtpCts));

            // Start the thread that places the call.
            SIPCallDescriptor callDescriptor = new SIPCallDescriptor(
                SIPConstants.SIP_DEFAULT_USERNAME,
                null,
                callUri.ToString(),
                SIPConstants.SIP_DEFAULT_FROMURI,
                null, null, null, null,
                SIPCallDirection.Out,
                SDP.SDP_MIME_CONTENTTYPE,
                GetSDP(rtpSocket.LocalEndPoint as IPEndPoint, RTPPayloadTypesEnum.PCMU).ToString(),
                null);

            uac.Call(callDescriptor);

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

            // At this point the call has been initiated and everything will be handled in an event handler or on the RTP
            // receive task. The code below is to gracefully exit.
            Task.Delay(3000).Wait();

            // Add some DTMF events to the queue. These will be transmitted by the SendRtp thread.
            _dtmfEvents.Enqueue(new RTPEvent(0x05, false, RTPEvent.DEFAULT_VOLUME, 1200, DTMF_EVENT_PAYLOAD_ID));
            Task.Delay(2000, rtpCts.Token).Wait();
            _dtmfEvents.Enqueue(new RTPEvent(0x09, false, RTPEvent.DEFAULT_VOLUME, 1200, DTMF_EVENT_PAYLOAD_ID));
            Task.Delay(2000, rtpCts.Token).Wait();
            _dtmfEvents.Enqueue(new RTPEvent(0x02, false, RTPEvent.DEFAULT_VOLUME, 1200, DTMF_EVENT_PAYLOAD_ID));
            Task.Delay(2000, rtpCts.Token).Wait();

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

            rtpCts.Cancel();
            rtpSocket?.Close();
            controlSocket?.Close();

            if (!isCallHungup && uac != null)
            {
                if (uac.IsUACAnswered)
                {
                    Log.LogInformation($"Hanging up call to {uac.CallDescriptor.To}.");
                    uac.Hangup();
                }
                else if (!hasCallFailed)
                {
                    Log.LogInformation($"Cancelling call to {uac.CallDescriptor.To}.");
                    uac.Cancel();
                }

                // Give the BYE or CANCEL request time to be transmitted.
                Log.LogInformation("Waiting 1s for call to clean up...");
                Task.Delay(1000).Wait();
            }

            SIPSorcery.Net.DNSManager.Stop();

            if (sipTransport != null)
            {
                Log.LogInformation("Shutting down SIP transport...");
                sipTransport.Shutdown();
            }
        }
Exemple #23
0
        static void Main()
        {
            Console.WriteLine("SIPSorcery client user agent example.");
            Console.WriteLine("Press ctrl-c to exit.");

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

            AddConsoleLogger();

            SIPURI callUri = SIPURI.ParseSIPURI(DEFAULT_DESTINATION_SIP_URI);

            Log.LogInformation($"Call destination {callUri}.");

            // Set up a default SIP transport.
            var sipTransport = new SIPTransport();
            int port         = SIPConstants.DEFAULT_SIP_PORT + 1000;

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

            // Uncomment this line to see each SIP message sent and received.
            EnableTraceLogs(sipTransport);

            // Send an OPTIONS request to determine the local IP address to use for the RTP socket.
            var optionsTask = SendOptionsTaskAsync(sipTransport, callUri);
            var result      = Task.WhenAny(optionsTask, Task.Delay(SIP_REQUEST_TIMEOUT_MILLISECONDS));

            result.Wait();

            if (optionsTask.IsCompletedSuccessfully == false || optionsTask.Result == null)
            {
                Log.LogError($"OPTIONS request to {callUri} failed.");
            }
            else
            {
                IPAddress localIPAddress = optionsTask.Result;

                // Initialise an RTP session to receive the RTP packets from the remote SIP server.
                Socket rtpSocket     = null;
                Socket controlSocket = null;
                NetServices.CreateRtpSocket(localIPAddress, 49000, 49100, false, out rtpSocket, out controlSocket);
                var rtpRecvSession = new RTPSession((int)RTPPayloadTypesEnum.PCMU, null, null);
                var rtpSendSession = new RTPSession((int)RTPPayloadTypesEnum.PCMU, null, null);

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

                uac.CallTrying += (uac, resp) =>
                {
                    Log.LogInformation($"{uac.CallDescriptor.To} Trying: {resp.StatusCode} {resp.ReasonPhrase}.");
                    Log.LogDebug(resp.ToString());
                };
                uac.CallRinging += (uac, resp) => Log.LogInformation($"{uac.CallDescriptor.To} Ringing: {resp.StatusCode} {resp.ReasonPhrase}.");
                uac.CallFailed  += (uac, err) =>
                {
                    Log.LogWarning($"{uac.CallDescriptor.To} Failed: {err}");
                    hasCallFailed = true;
                };
                uac.CallAnswered += (uac, resp) =>
                {
                    if (resp.Status == SIPResponseStatusCodesEnum.Ok)
                    {
                        Log.LogInformation($"{uac.CallDescriptor.To} Answered: {resp.StatusCode} {resp.ReasonPhrase}.");

                        _remoteRtpEndPoint = SDP.GetSDPRTPEndPoint(resp.Body);

                        Log.LogDebug($"Remote RTP socket {_remoteRtpEndPoint}.");
                    }
                    else
                    {
                        Log.LogWarning($"{uac.CallDescriptor.To} Answered: {resp.StatusCode} {resp.ReasonPhrase}.");
                    }
                };

                // The only incoming request that needs to be explicitly handled for this example is if the remote end hangs up the call.
                sipTransport.SIPTransportRequestReceived += (SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPRequest sipRequest) =>
                {
                    if (sipRequest.Method == SIPMethodsEnum.BYE)
                    {
                        SIPNonInviteTransaction byeTransaction = sipTransport.CreateNonInviteTransaction(sipRequest, remoteEndPoint, localSIPEndPoint, null);
                        SIPResponse             byeResponse    = SIPTransport.GetResponse(sipRequest, SIPResponseStatusCodesEnum.Ok, null);
                        byeTransaction.SendFinalResponse(byeResponse);

                        if (uac.IsUACAnswered)
                        {
                            Log.LogInformation("Call was hungup by remote server.");
                            isCallHungup = true;
                            rtpCts.Cancel();
                        }
                    }
                };

                // It's a good idea to start the RTP receiving socket before the call request is sent.
                // A SIP server will generally start sending RTP as soon as it has processed the incoming call request and
                // being ready to receive will stop any ICMP error response being generated.
                Task.Run(() => RecvRtp(rtpSocket, rtpRecvSession, rtpCts));
                Task.Run(() => SendRtp(rtpSocket, rtpSendSession, rtpCts));

                // Start the thread that places the call.
                SIPCallDescriptor callDescriptor = new SIPCallDescriptor(
                    SIPConstants.SIP_DEFAULT_USERNAME,
                    null,
                    callUri.ToString(),
                    SIPConstants.SIP_DEFAULT_FROMURI,
                    null, null, null, null,
                    SIPCallDirection.Out,
                    SDP.SDP_MIME_CONTENTTYPE,
                    GetSDP(rtpSocket.LocalEndPoint as IPEndPoint).ToString(),
                    null);

                uac.Call(callDescriptor);

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

                // At this point the call is established. We'll wait for a few seconds and then transfer.
                Task.Delay(DELAY_UNTIL_TRANSFER_MILLISECONDS).Wait();

                SIPRequest referRequest         = GetReferRequest(uac, SIPURI.ParseSIPURI(TRANSFER_DESTINATION_SIP_URI));
                SIPNonInviteTransaction referTx = sipTransport.CreateNonInviteTransaction(referRequest, referRequest.RemoteSIPEndPoint, referRequest.LocalSIPEndPoint, null);

                referTx.NonInviteTransactionFinalResponseReceived += (SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPTransaction sipTransaction, SIPResponse sipResponse) =>
                {
                    if (sipResponse.Header.CSeqMethod == SIPMethodsEnum.REFER && sipResponse.Status == SIPResponseStatusCodesEnum.Accepted)
                    {
                        Log.LogInformation("Call transfer was accepted by remote server.");
                        isCallHungup = true;
                        rtpCts.Cancel();
                    }
                };

                referTx.SendReliableRequest();

                // At this point the call transfer has been initiated and everything will be handled in an event handler or on the RTP
                // receive task. The code below is to gracefully exit.

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

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

                rtpSocket?.Close();
                controlSocket?.Close();

                if (!isCallHungup && uac != null)
                {
                    if (uac.IsUACAnswered)
                    {
                        Log.LogInformation($"Hanging up call to {uac.CallDescriptor.To}.");
                        uac.Hangup();
                    }
                    else if (!hasCallFailed)
                    {
                        Log.LogInformation($"Cancelling call to {uac.CallDescriptor.To}.");
                        uac.Cancel();
                    }

                    // Give the BYE or CANCEL request time to be transmitted.
                    Log.LogInformation("Waiting 1s for call to clean up...");
                    Task.Delay(1000).Wait();
                }
            }

            SIPSorcery.Net.DNSManager.Stop();

            if (sipTransport != null)
            {
                Log.LogInformation("Shutting down SIP transport...");
                sipTransport.Shutdown();
            }
        }
Exemple #24
0
        static void Main()
        {
            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 trnasport and RTP stream.
            bool isCallHungup  = false;
            bool hasCallFailed = false;

            AddConsoleLogger();

            SIPURI callUri = SIPURI.ParseSIPURI(DEFAULT_DESTINATION_SIP_URI);

            Log.LogInformation($"Call destination {callUri}.");

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

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

            EnableTraceLogs(sipTransport);

            var lookupResult = SIPDNSManager.ResolveSIPService(callUri, false);

            Log.LogDebug($"DNS lookup result for {callUri}: {lookupResult?.GetSIPEndPoint()}.");
            var dstAddress = lookupResult.GetSIPEndPoint().Address;

            IPAddress localIPAddress = NetServices.GetLocalAddressForRemote(dstAddress);

            // Initialise an RTP session to receive the RTP packets from the remote SIP server.
            Socket rtpSocket     = null;
            Socket controlSocket = null;

            NetServices.CreateRtpSocket(localIPAddress, 48000, 48100, false, out rtpSocket, out controlSocket);
            var rtpRecvSession = new RTPSession((int)RTPPayloadTypesEnum.PCMU, null, null);
            var rtpSendSession = new RTPSession((int)RTPPayloadTypesEnum.PCMU, null, null);

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

            uac.CallTrying += (uac, resp) =>
            {
                Log.LogInformation($"{uac.CallDescriptor.To} Trying: {resp.StatusCode} {resp.ReasonPhrase}.");
            };
            uac.CallRinging += (uac, resp) => Log.LogInformation($"{uac.CallDescriptor.To} Ringing: {resp.StatusCode} {resp.ReasonPhrase}.");
            uac.CallFailed  += (uac, err) =>
            {
                Log.LogWarning($"{uac.CallDescriptor.To} Failed: {err}");
                hasCallFailed = true;
            };
            uac.CallAnswered += (uac, resp) =>
            {
                if (resp.Status == SIPResponseStatusCodesEnum.Ok)
                {
                    Log.LogInformation($"{uac.CallDescriptor.To} Answered: {resp.StatusCode} {resp.ReasonPhrase}.");

                    // Only set the remote RTP end point if there hasn't already been a packet received on it.
                    if (_remoteRtpEndPoint == null)
                    {
                        _remoteRtpEndPoint = SDP.GetSDPRTPEndPoint(resp.Body);
                        Log.LogDebug($"Remote RTP socket {_remoteRtpEndPoint}.");
                    }
                }
                else
                {
                    Log.LogWarning($"{uac.CallDescriptor.To} Answered: {resp.StatusCode} {resp.ReasonPhrase}.");
                }
            };

            // The only incoming request that needs to be explicitly handled for this example is if the remote end hangs up the call.
            sipTransport.SIPTransportRequestReceived += (SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPRequest sipRequest) =>
            {
                if (sipRequest.Method == SIPMethodsEnum.BYE)
                {
                    SIPNonInviteTransaction byeTransaction = sipTransport.CreateNonInviteTransaction(sipRequest, null);
                    SIPResponse             byeResponse    = SIPTransport.GetResponse(sipRequest, SIPResponseStatusCodesEnum.Ok, null);
                    byeTransaction.SendFinalResponse(byeResponse);

                    if (uac.IsUACAnswered)
                    {
                        Log.LogInformation("Call was hungup by remote server.");
                        isCallHungup = true;
                        exitCts.Cancel();
                    }
                }
            };

            // It's a good idea to start the RTP receiving socket before the call request is sent.
            // A SIP server will generally start sending RTP as soon as it has processed the incoming call request and
            // being ready to receive will stop any ICMP error response being generated.
            Task.Run(() => RecvRtp(rtpSocket, rtpRecvSession, exitCts));
            Task.Run(() => SendRtp(rtpSocket, rtpSendSession, exitCts));

            // Start the thread that places the call.
            SIPCallDescriptor callDescriptor = new SIPCallDescriptor(
                SIP_USERNAME,
                SIP_PASSWORD,
                callUri.ToString(),
                $"sip:{SIP_USERNAME}@localhost",
                callUri.CanonicalAddress,
                null, null, null,
                SIPCallDirection.Out,
                SDP.SDP_MIME_CONTENTTYPE,
                GetSDP(rtpSocket.LocalEndPoint as IPEndPoint).ToString(),
                null);

            uac.Call(callDescriptor);

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

            // At this point the call has been initiated and everything will be handled in an event handler.

            Task.Run(() =>
            {
                try
                {
                    while (!exitCts.Token.WaitHandle.WaitOne(0))
                    {
                        var keyProps = Console.ReadKey();
                        if (keyProps.KeyChar == 'h')
                        {
                        }
                        else if (keyProps.KeyChar == 'q')
                        {
                            Console.WriteLine();
                            Console.WriteLine("Hangup requested by user...");

                            uac.Hangup();

                            exitCts.Cancel();
                            rtpSocket?.Close();
                            controlSocket?.Close();

                            SIPSorcery.Sys.Log.Logger.LogInformation("Quitting...");

                            if (sipTransport != null)
                            {
                                SIPSorcery.Sys.Log.Logger.LogInformation("Shutting down SIP transport...");
                                sipTransport.Shutdown();
                            }
                        }
                    }
                }
                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();

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

            rtpSocket?.Close();
            controlSocket?.Close();

            if (!isCallHungup && uac != null)
            {
                if (uac.IsUACAnswered)
                {
                    Log.LogInformation($"Hanging up call to {uac.CallDescriptor.To}.");
                    uac.Hangup();
                }
                else if (!hasCallFailed)
                {
                    Log.LogInformation($"Cancelling call to {uac.CallDescriptor.To}.");
                    uac.Cancel();
                }

                // Give the BYE or CANCEL request time to be transmitted.
                Log.LogInformation("Waiting 1s for call to clean up...");
                Task.Delay(1000).Wait();
            }

            SIPSorcery.Net.DNSManager.Stop();

            if (sipTransport != null)
            {
                Log.LogInformation("Shutting down SIP transport...");
                sipTransport.Shutdown();
            }
        }
Exemple #25
0
        static async Task Main(string[] args)
        {
            Console.WriteLine("SIPSorcery client user agent example.");
            Console.WriteLine("Press ctrl-c to exit.");

            // Plumbing code to facilitate a graceful exit.
            ManualResetEvent exitMre       = new ManualResetEvent(false);
            bool             isCallHungup  = false;
            bool             hasCallFailed = false;

            AddConsoleLogger();

            SIPURI callUri = SIPURI.ParseSIPURI(DEFAULT_DESTINATION_SIP_URI);

            if (args != null && args.Length > 0)
            {
                if (!SIPURI.TryParse(args[0], out callUri))
                {
                    Log.LogWarning($"Command line argument could not be parsed as a SIP URI {args[0]}");
                }
            }
            Log.LogInformation($"Call destination {callUri}.");

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

            EnableTraceLogs(sipTransport);

            // Get the IP address the RTP will be sent from. While we can listen on IPAddress.Any | IPv6Any
            // we can't put 0.0.0.0 or [::0] in the SDP or the callee will treat our RTP stream as inactive.
            var lookupResult = SIPDNSManager.ResolveSIPService(callUri, false);

            Log.LogDebug($"DNS lookup result for {callUri}: {lookupResult?.GetSIPEndPoint()}.");
            var dstAddress = lookupResult.GetSIPEndPoint().Address;

            // Initialise an RTP session to receive the RTP packets from the remote SIP server.
            var rtpSession = new RtpAVSession(dstAddress.AddressFamily, new AudioOptions {
                AudioSource = AudioSourcesEnum.Microphone
            }, null);
            var offerSDP = await rtpSession.createOffer(new RTCOfferOptions { RemoteSignallingAddress = dstAddress });

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

            uac.CallTrying  += (uac, resp) => Log.LogInformation($"{uac.CallDescriptor.To} Trying: {resp.StatusCode} {resp.ReasonPhrase}.");
            uac.CallRinging += (uac, resp) => Log.LogInformation($"{uac.CallDescriptor.To} Ringing: {resp.StatusCode} {resp.ReasonPhrase}.");
            uac.CallFailed  += (uac, err) =>
            {
                Log.LogWarning($"{uac.CallDescriptor.To} Failed: {err}");
                hasCallFailed = true;
            };
            uac.CallAnswered += (uac, resp) =>
            {
                if (resp.Status == SIPResponseStatusCodesEnum.Ok)
                {
                    Log.LogInformation($"{uac.CallDescriptor.To} Answered: {resp.StatusCode} {resp.ReasonPhrase}.");

                    rtpSession.setRemoteDescription(new RTCSessionDescription {
                        type = RTCSdpType.answer, sdp = SDP.ParseSDPDescription(resp.Body)
                    });
                    rtpSession.Start();
                }
                else
                {
                    Log.LogWarning($"{uac.CallDescriptor.To} Answered: {resp.StatusCode} {resp.ReasonPhrase}.");
                }
            };

            // The only incoming request that needs to be explicitly handled for this example is if the remote end hangs up the call.
            sipTransport.SIPTransportRequestReceived += async(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPRequest sipRequest) =>
            {
                if (sipRequest.Method == SIPMethodsEnum.BYE)
                {
                    SIPResponse okResponse = SIPResponse.GetResponse(sipRequest, SIPResponseStatusCodesEnum.Ok, null);
                    await sipTransport.SendResponseAsync(okResponse);

                    if (uac.IsUACAnswered)
                    {
                        Log.LogInformation("Call was hungup by remote server.");
                        isCallHungup = true;
                        exitMre.Set();
                    }
                }
            };

            // Start the thread that places the call.
            SIPCallDescriptor callDescriptor = new SIPCallDescriptor(
                SIPConstants.SIP_DEFAULT_USERNAME,
                null,
                callUri.ToString(),
                SIPConstants.SIP_DEFAULT_FROMURI,
                callUri.CanonicalAddress,
                null, null, null,
                SIPCallDirection.Out,
                SDP.SDP_MIME_CONTENTTYPE,
                offerSDP.ToString(),
                null);

            uac.Call(callDescriptor);
            uac.ServerTransaction.TransactionTraceMessage += (tx, msg) => Log.LogInformation($"UAC tx trace message. {msg}");

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

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

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

            rtpSession.CloseSession(null);

            if (!isCallHungup && uac != null)
            {
                if (uac.IsUACAnswered)
                {
                    Log.LogInformation($"Hanging up call to {uac.CallDescriptor.To}.");
                    uac.Hangup();
                }
                else if (!hasCallFailed)
                {
                    Log.LogInformation($"Cancelling call to {uac.CallDescriptor.To}.");
                    uac.Cancel();
                }

                // Give the BYE or CANCEL request time to be transmitted.
                Log.LogInformation("Waiting 1s for call to clean up...");
                Task.Delay(1000).Wait();
            }

            SIPSorcery.Net.DNSManager.Stop();

            if (sipTransport != null)
            {
                Log.LogInformation("Shutting down SIP transport...");
                sipTransport.Shutdown();
            }
        }
Exemple #26
0
        private void StartNewCallSync(SIPCallDescriptor callDescriptor)
        {
            try
            {
                callDescriptor.DialPlanContextID = (m_dialPlanContext != null) ? m_dialPlanContext.DialPlanContextID : Guid.Empty;

                if (callDescriptor.DelaySeconds != 0)
                {
                    callDescriptor.DelayMRE = new ManualResetEvent(false);
                    lock (m_delayedCalls)
                    {
                        m_delayedCalls.Add(callDescriptor);
                    }

                    int delaySeconds = (callDescriptor.DelaySeconds > MAX_DELAY_SECONDS) ? MAX_DELAY_SECONDS : callDescriptor.DelaySeconds;
                    FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Delaying call leg to " + callDescriptor.Uri + " by " + delaySeconds + "s.", m_username));
                    callDescriptor.DelayMRE.WaitOne(delaySeconds * 1000);
                }

                lock (m_delayedCalls)
                {
                    m_delayedCalls.Remove(callDescriptor);
                }

                if (!m_callAnswered && !m_commandCancelled)
                {
                    ISIPClientUserAgent uacCall = null;

                    if (callDescriptor.ToSIPAccount == null)
                    {
                        if (callDescriptor.IsGoogleVoiceCall)
                        {
                            FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Creating Google Voice user agent for " + callDescriptor.Uri + ".", m_username));
                            uacCall = new GoogleVoiceUserAgent(m_sipTransport, m_callManager, m_statefulProxyLogEvent, m_username, m_adminMemberId, m_outboundProxySocket);
                        }
                        else
                        {
                            uacCall = new SIPClientUserAgent(m_sipTransport, m_outboundProxySocket, m_username, m_adminMemberId, m_statefulProxyLogEvent,
                                                             m_customerAccountDataLayer.GetRtccCustomer, m_customerAccountDataLayer.GetRtccRate, m_customerAccountDataLayer.GetBalance,
                                                             m_customerAccountDataLayer.ReserveInitialCredit, m_customerAccountDataLayer.UpdateRealTimeCallControlCDRID);
                        }
                    }
                    else
                    {
                        if (QueueNewCall_External == null)
                        {
                            FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "B2B calls are not supported in this dialplan manifestation.", m_username));
                        }
                        else
                        {
                            FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Creating B2B call for " + callDescriptor.Uri + ".", m_username));
                            uacCall = new SIPB2BUserAgent(m_statefulProxyLogEvent, QueueNewCall_External, m_sipTransport, m_username, m_adminMemberId);
                        }
                    }

                    //ISIPClientUserAgent uacCall = new JingleUserAgent(m_username, m_adminMemberId, m_statefulProxyLogEvent);

                    if (uacCall != null)
                    {
                        lock (m_switchCalls)
                        {
                            m_switchCalls.Add(uacCall);
                        }

                        uacCall.CallAnswered += UACCallAnswered;
                        uacCall.CallFailed   += UACCallFailed;
                        uacCall.CallRinging  += UACCallProgress;
                        //uacCall.CallTrying += UACCallTrying;

                        uacCall.Call(callDescriptor);
                    }
                }
            }
            catch (Exception excp)
            {
                logger.Error("Exception ForkCall StartNewCall. " + excp.Message);
            }
        }
Exemple #27
0
        /// <summary>
        /// Sends the SIP INVITE probe request.
        /// </summary>
        public void SendProbe()
        {
            try
            {
                if (WorkerProcess == null)
                {
                    logger.Debug("When attempting to send probe the worker process was null. Marking for immediate restart.");
                    NeedsImmediateRestart = true;
                }
                else if (WorkerProcess.HasExited)
                {
                    logger.Debug("When attempting to send probe the worker had exited. Marking for immediate restart.");
                    NeedsImmediateRestart = true;
                }
                else if (m_probeUAC != null && !m_probeUAC.IsUACAnswered)
                {
                    // A probe call has timed out.
                    m_probeUAC.Cancel();
                    m_missedProbes++;
                    if (m_missedProbes >= m_missedProbesLimit)
                    {
                        logger.Warn(m_missedProbes + " probes missed for " + AppServerEndpoint.ToString() + ". Marking for immediate restart.");
                        NeedsImmediateRestart = true;
                    }
                }

                if (!NeedsImmediateRestart && !NeedsToRestart)
                {
                    m_probeCount++;
                    //logger.Debug("Sending probe " + m_probeCount + " to " + AppServerEndpoint.GetIPEndPoint().ToString() + ".");
                    DateTime probeSentAt = DateTime.Now;

                    SIPCallDescriptor callDescriptor = new SIPCallDescriptor(m_dispatcherUsername, null, "sip:" + m_dispatcherUsername + "@" + AppServerEndpoint.GetIPEndPoint().ToString(),
                                                                             "sip:" + m_dispatcherUsername + "@sipcalldispatcher", "sip:" + AppServerEndpoint.GetIPEndPoint().ToString(), null, null, null, SIPCallDirection.Out, null, null, null);
                    m_probeUAC = new SIPClientUserAgent(m_sipTransport, null, null, null, null, null, null, null, null, null);

                    m_probeUAC.CallAnswered += (call, sipResponse) =>
                    {
                        //logger.Debug("Probe response received for " + AppServerEndpoint.ToString() + ".");
                        if (sipResponse.Status != SIPResponseStatusCodesEnum.BadExtension)
                        //if (sipResponse.Status != SIPResponseStatusCodesEnum.InternalServerError)
                        {
                            logger.Warn("Probe to " + AppServerEndpoint.ToString() + " answered incorrectly on probe number " + m_probeCount + " after "
                                        + DateTime.Now.Subtract(probeSentAt).TotalSeconds.ToString("0.##") + "s, unexpected response of " + ((int)sipResponse.StatusCode) + ".");
                            NeedsImmediateRestart = true;
                        }
                        else
                        {
                            m_gotInitialProbeResponse = true;
                        }

                        if (m_initialResponseMRE != null)
                        {
                            m_initialResponseMRE.Set();
                        }
                    };

                    m_probeUAC.Call(callDescriptor);
                }
            }
            catch (Exception excp)
            {
                logger.Error("Exception SendProbe. " + excp.Message);
            }
        }
Exemple #28
0
        static void Main(string[] args)
        {
            Console.WriteLine("SIPSorcery client user agent example.");
            Console.WriteLine("Press ctrl-c to exit.");

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

            // 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;

            SIPURI callUri = SIPURI.ParseSIPURI(DEFAULT_DESTINATION_SIP_URI);

            if (args != null && args.Length > 0)
            {
                if (!SIPURI.TryParse(args[0]))
                {
                    Log.LogWarning($"Command line argument could not be parsed as a SIP URI {args[0]}");
                }
                else
                {
                    callUri = SIPURI.ParseSIPURIRelaxed(args[0]);
                }
            }

            Log.LogInformation($"Call destination {callUri}.");

            // Set up a default SIP transport.
            var       sipTransport = new SIPTransport();
            int       port         = SIPConstants.DEFAULT_SIP_PORT + 1000;
            IPAddress localAddress = sipTransport.GetLocalAddress(IPAddress.Parse("8.8.8.8"));

            sipTransport.AddSIPChannel(new SIPUDPChannel(new IPEndPoint(localAddress, port)));
            //sipTransport.AddSIPChannel(new SIPUDPChannel(new IPEndPoint(IPAddress.Any, port)));
            //sipTransport.AddSIPChannel(new SIPUDPChannel(new IPEndPoint(IPAddress.IPv6Any, port)));

            //EnableTraceLogs(sipTransport);

            // Select the IP address to use for RTP based on the destination SIP URI.
            var endPointForCall = callUri.ToSIPEndPoint() == null?sipTransport.GetDefaultSIPEndPoint(callUri.Protocol) : sipTransport.GetDefaultSIPEndPoint(callUri.ToSIPEndPoint());

            // Initialise an RTP session to receive the RTP packets from the remote SIP server.
            Socket rtpSocket     = null;
            Socket controlSocket = null;
            // TODO (find something better): If the SIP endpoint is using 0.0.0.0 for SIP use loopback for RTP.
            IPAddress rtpAddress = localAddress;

            NetServices.CreateRtpSocket(rtpAddress, 49000, 49100, false, out rtpSocket, out controlSocket);
            var rtpSendSession = new RTPSession((int)RTPPayloadTypesEnum.PCMU, null, null);

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

            uac.CallTrying += (uac, resp) =>
            {
                Log.LogInformation($"{uac.CallDescriptor.To} Trying: {resp.StatusCode} {resp.ReasonPhrase}.");
            };
            uac.CallRinging += (uac, resp) => Log.LogInformation($"{uac.CallDescriptor.To} Ringing: {resp.StatusCode} {resp.ReasonPhrase}.");
            uac.CallFailed  += (uac, err) =>
            {
                Log.LogWarning($"{uac.CallDescriptor.To} Failed: {err}");
                hasCallFailed = true;
            };
            uac.CallAnswered += (uac, resp) =>
            {
                if (resp.Status == SIPResponseStatusCodesEnum.Ok)
                {
                    Log.LogInformation($"{uac.CallDescriptor.To} Answered: {resp.StatusCode} {resp.ReasonPhrase}.");

                    IPEndPoint remoteRtpEndPoint = SDP.GetSDPRTPEndPoint(resp.Body);

                    Log.LogDebug($"Sending initial RTP packet to remote RTP socket {remoteRtpEndPoint}.");

                    // Send a dummy packet to open the NAT session on the RTP path.
                    rtpSendSession.SendAudioFrame(rtpSocket, remoteRtpEndPoint, 0, new byte[] { 0x00 });
                }
                else
                {
                    Log.LogWarning($"{uac.CallDescriptor.To} Answered: {resp.StatusCode} {resp.ReasonPhrase}.");
                }
            };

            // The only incoming request that needs to be explicitly handled for this example is if the remote end hangs up the call.
            sipTransport.SIPTransportRequestReceived += (SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPRequest sipRequest) =>
            {
                if (sipRequest.Method == SIPMethodsEnum.BYE)
                {
                    SIPNonInviteTransaction byeTransaction = sipTransport.CreateNonInviteTransaction(sipRequest, remoteEndPoint, localSIPEndPoint, null);
                    SIPResponse             byeResponse    = SIPTransport.GetResponse(sipRequest, SIPResponseStatusCodesEnum.Ok, null);
                    byeTransaction.SendFinalResponse(byeResponse);

                    if (uac.IsUACAnswered)
                    {
                        Log.LogInformation("Call was hungup by remote server.");
                        isCallHungup = true;
                        rtpCts.Cancel();
                    }
                }
            };

            // It's a good idea to start the RTP receiving socket before the call request is sent.
            // A SIP server will generally start sending RTP as soon as it has processed the incoming call request and
            // being ready to receive will stop any ICMP error response being generated.
            Task.Run(() => SendRecvRtp(rtpSocket, rtpSendSession, rtpCts));

            // Start the thread that places the call.
            SIPCallDescriptor callDescriptor = new SIPCallDescriptor(
                SIPConstants.SIP_DEFAULT_USERNAME,
                null,
                callUri.ToString(),
                SIPConstants.SIP_DEFAULT_FROMURI,
                null, null, null, null,
                SIPCallDirection.Out,
                SDP.SDP_MIME_CONTENTTYPE,
                GetSDP(rtpSocket.LocalEndPoint as IPEndPoint).ToString(),
                null);

            uac.Call(callDescriptor);

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

            // At this point the call has been initiated and everything will be handled in an event handler or on the RTP
            // receive task. The code below is to gracefully exit.

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

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

            rtpSocket?.Close();
            controlSocket?.Close();

            if (!isCallHungup && uac != null)
            {
                if (uac.IsUACAnswered)
                {
                    Log.LogInformation($"Hanging up call to {uac.CallDescriptor.To}.");
                    uac.Hangup();
                }
                else if (!hasCallFailed)
                {
                    Log.LogInformation($"Cancelling call to {uac.CallDescriptor.To}.");
                    uac.Cancel();
                }

                // Give the BYE or CANCEL request time to be transmitted.
                Log.LogInformation("Waiting 1s for call to clean up...");
                Task.Delay(1000).Wait();
            }

            SIPSorcery.Net.DNSManager.Stop();

            if (sipTransport != null)
            {
                Log.LogInformation("Shutting down SIP transport...");
                sipTransport.Shutdown();
            }
        }
Exemple #29
0
        private static readonly int RTP_REPORTING_PERIOD_SECONDS = 5;       // Period at which to write RTP stats.

        static void Main()
        {
            Console.WriteLine("SIPSorcery client user agent example.");
            Console.WriteLine("Press ctrl-c to exit.");

            // Plumbing code to facilitate a graceful exit.
            CancellationTokenSource cts = new CancellationTokenSource();
            bool isCallHungup           = false;
            bool hasCallFailed          = false;

            // 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.
            IPAddress defaultAddr  = LocalIPConfig.GetDefaultIPv4Address();
            var       sipTransport = new SIPTransport(SIPDNSManager.ResolveSIPService, new SIPTransactionEngine());
            int       port         = FreePort.FindNextAvailableUDPPort(SIPConstants.DEFAULT_SIP_PORT + 2);
            var       sipChannel   = new SIPUDPChannel(new IPEndPoint(defaultAddr, port));

            sipTransport.AddSIPChannel(sipChannel);

            // Initialise an RTP session to receive the RTP packets from the remote SIP server.
            Socket rtpSocket     = null;
            Socket controlSocket = null;

            NetServices.CreateRtpSocket(defaultAddr, 49000, 49100, false, out rtpSocket, out controlSocket);
            var rtpSendSession = new RTPSession((int)RTPPayloadTypesEnum.PCMU, null, null);

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

            uac.CallTrying  += (uac, resp) => SIPSorcery.Sys.Log.Logger.LogInformation($"{uac.CallDescriptor.To} Trying: {resp.StatusCode} {resp.ReasonPhrase}.");
            uac.CallRinging += (uac, resp) => SIPSorcery.Sys.Log.Logger.LogInformation($"{uac.CallDescriptor.To} Ringing: {resp.StatusCode} {resp.ReasonPhrase}.");
            uac.CallFailed  += (uac, err) =>
            {
                SIPSorcery.Sys.Log.Logger.LogWarning($"{uac.CallDescriptor.To} Failed: {err}");
                hasCallFailed = true;
            };
            uac.CallAnswered += (uac, resp) =>
            {
                if (resp.Status == SIPResponseStatusCodesEnum.Ok)
                {
                    SIPSorcery.Sys.Log.Logger.LogInformation($"{uac.CallDescriptor.To} Answered: {resp.StatusCode} {resp.ReasonPhrase}.");
                    IPEndPoint remoteRtpEndPoint = SDP.GetSDPRTPEndPoint(resp.Body);

                    SIPSorcery.Sys.Log.Logger.LogDebug($"Sending initial RTP packet to remote RTP socket {remoteRtpEndPoint}.");

                    // Send a dummy packet to open the NAT session on the RTP path.
                    rtpSendSession.SendAudioFrame(rtpSocket, remoteRtpEndPoint, 0, new byte[] { 0x00 });
                }
                else
                {
                    SIPSorcery.Sys.Log.Logger.LogWarning($"{uac.CallDescriptor.To} Answered: {resp.StatusCode} {resp.ReasonPhrase}.");
                }
            };

            // The only incoming request that needs to be explicitly handled for this example is if the remote end hangs up the call.
            sipTransport.SIPTransportRequestReceived += (SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPRequest sipRequest) =>
            {
                if (sipRequest.Method == SIPMethodsEnum.BYE)
                {
                    SIPNonInviteTransaction byeTransaction = sipTransport.CreateNonInviteTransaction(sipRequest, remoteEndPoint, localSIPEndPoint, null);
                    SIPResponse             byeResponse    = SIPTransport.GetResponse(sipRequest, SIPResponseStatusCodesEnum.Ok, null);
                    byeTransaction.SendFinalResponse(byeResponse);

                    if (uac.IsUACAnswered)
                    {
                        SIPSorcery.Sys.Log.Logger.LogInformation("Call was hungup by remote server.");
                        isCallHungup = true;
                        cts.Cancel();
                    }
                }
            };

            // It's a good idea to start the RTP receiving socket before the call request is sent.
            // A SIP server will generally start sending RTP as soon as it has processed the incoming call request and
            // being ready to receive will stop any ICMP error response being generated.
            Task.Run(() => SendRecvRtp(rtpSocket, rtpSendSession, cts));

            // Start the thread that places the call.
            SIPCallDescriptor callDescriptor = new SIPCallDescriptor(
                SIPConstants.SIP_DEFAULT_USERNAME,
                null,
                DESTINATION_SIP_URI,
                SIPConstants.SIP_DEFAULT_FROMURI,
                null, null, null, null,
                SIPCallDirection.Out,
                SDP.SDP_MIME_CONTENTTYPE,
                GetSDP(rtpSocket.LocalEndPoint as IPEndPoint).ToString(),
                null);

            uac.Call(callDescriptor);

            // At this point the call has been initiated and everything will be handled in an event handler or on the RTP
            // receive task. The code below is to gracefully exit.
            // Ctrl-c will gracefully exit the call at any point.
            Console.CancelKeyPress += async delegate(object sender, ConsoleCancelEventArgs e)
            {
                e.Cancel = true;
                cts.Cancel();

                SIPSorcery.Sys.Log.Logger.LogInformation("Exiting...");

                rtpSocket?.Close();
                controlSocket?.Close();

                if (!isCallHungup && uac != null)
                {
                    if (uac.IsUACAnswered)
                    {
                        SIPSorcery.Sys.Log.Logger.LogInformation($"Hanging up call to {uac.CallDescriptor.To}.");
                        uac.Hangup();
                    }
                    else if (!hasCallFailed)
                    {
                        SIPSorcery.Sys.Log.Logger.LogInformation($"Cancelling call to {uac.CallDescriptor.To}.");
                        uac.Cancel();
                    }

                    // Give the BYE or CANCEL request time to be transmitted.
                    SIPSorcery.Sys.Log.Logger.LogInformation("Waiting 1s for call to clean up...");
                    await Task.Delay(1000);
                }

                SIPSorcery.Net.DNSManager.Stop();

                if (sipTransport != null)
                {
                    SIPSorcery.Sys.Log.Logger.LogInformation("Shutting down SIP transport...");
                    sipTransport.Shutdown();
                }
            };
        }
Exemple #30
0
        static async Task Main()
        {
            Console.WriteLine("SIPSorcery Getting Started Demo");

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

            var sipTransport = new SIPTransport();

            EnableTraceLogs(sipTransport);

            var userAgent = new SIPUserAgent(sipTransport, OUTBOUND_PROXY);

            userAgent.ClientCallFailed += (uac, error, sipResponse) => Console.WriteLine($"Call failed {error}.");
            userAgent.OnCallHungup     += (dialog) => exitCts.Cancel();

            var windowsAudio     = new WindowsAudioEndPoint(new AudioEncoder());
            var voipMediaSession = new VoIPMediaSession(windowsAudio.ToMediaEndPoints());

            voipMediaSession.AcceptRtpFromAny     = true;
            voipMediaSession.OnRtpPacketReceived += OnRtpPacketReceived;

            string            fromHeader     = (new SIPFromHeader(USERNAME, new SIPURI(USERNAME, DOMAIN, null), null)).ToString();
            SIPCallDescriptor callDescriptor = new SIPCallDescriptor(USERNAME, PASSWORD, DESTINATION, fromHeader, null, null, null, null, SIPCallDirection.Out, SDP.SDP_MIME_CONTENTTYPE, null, null);
            //callDescriptor.CallId = "16152412565";
            //callDescriptor.AuthUsername = USERNAME;

            // Place the call and wait for the result.
            var callTask = userAgent.Call(callDescriptor, voipMediaSession);

            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();
                        _waveFile.Dispose();
                    }
                }
                ;

                exitCts.Cancel();
            };

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

            bool callResult = await callTask;


            if (callResult)
            {
                Console.WriteLine("Enter digits one after another");
                string meetingNo = "1711622132";
                Console.WriteLine("Enter meetingno ?");
                Console.ReadLine();
                foreach (var item in meetingNo)
                {
                    await userAgent.SendDtmf(byte.Parse(item.ToString()));

                    Console.WriteLine("Sending DTMF - " + byte.Parse(item.ToString()));
                    Thread.Sleep(2000);
                }
                Thread.Sleep(2000);
                await userAgent.SendDtmf(Encoding.ASCII.GetBytes("#")[0]);

                Thread.Sleep(13000);
                Console.WriteLine("Sending AttendeeID ?");

                /*string attendeeId = "635619";
                 * foreach (var item in attendeeId)
                 * {
                 *  await userAgent.SendDtmf(byte.Parse(item.ToString()));
                 *  Console.WriteLine("Sending DTMF - " + byte.Parse(item.ToString()));
                 *  Thread.Sleep(2000);
                 * }*/
                await userAgent.SendDtmf(Encoding.ASCII.GetBytes("#")[0]);

                Console.ReadLine();
                await userAgent.SendDtmf(Encoding.ASCII.GetBytes("#")[0]);

                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();
        }