Esempio n. 1
0
        /// <summary>
        /// Puts the remote call party on hold.
        /// </summary>
        public async Task PutOnHold()
        {
            await MediaSession.PutOnHold();

            m_userAgent.PutOnHold();
            StatusMessage(this, "Local party put on hold");
        }
Esempio n. 2
0
        /// <summary>
        /// Puts the remote call party on hold.
        /// </summary>
        public async void PutOnHold()
        {
            bool hasAudio = MediaSession.HasAudio;
            bool hasVideo = MediaSession.HasVideo;

            m_userAgent.PutOnHold();

            AudioOptions audioOnHold = (!hasAudio) ? null :
                                       new AudioOptions
            {
                AudioSource       = AudioSourcesEnum.Music,
                OutputDeviceIndex = m_audioOutDeviceIndex,
                SourceFiles       = new Dictionary <SDPMediaFormatsEnum, string>
                {
                    { SDPMediaFormatsEnum.PCMU, MUSIC_FILE_PCMU },
                    { SDPMediaFormatsEnum.PCMA, MUSIC_FILE_PCMA }
                }
            };
            VideoOptions videoOnHold = null;

            if (hasVideo)
            {
                //if (bmpSource != null)
                //{
                //    videoOnHold = new VideoOptions
                //    {
                //        VideoSource = VideoSourcesEnum.ExternalBitmap,
                //        BitmapSource = bmpSource
                //    };
                //}
                //else
                //{
                videoOnHold = new VideoOptions
                {
                    VideoSource           = VideoSourcesEnum.TestPattern,
                    SourceFile            = RtpAVSession.VIDEO_ONHOLD_TESTPATTERN,
                    SourceFramesPerSecond = VIDEO_ONHOLD_FRAMES_PER_SECOND
                };
                //}
            }

            await MediaSession.SetSources(audioOnHold, videoOnHold);

            // At this point we could stop listening to the remote party's RTP and play something
            // else and also stop sending our microphone output and play some music.
            StatusMessage(this, "Local party put on hold");
        }
Esempio n. 3
0
        /// <summary>
        /// Puts the remote call party on hold.
        /// </summary>
        public async void PutOnHold()
        {
            await m_userAgent.PutOnHold();

            if (MediaSession is RtpAVSession)
            {
                AudioOptions audioOnHold = (!MediaSession.HasAudio) ? null : new AudioOptions {
                    AudioSource = AudioSourcesEnum.Music
                };
                VideoOptions videoOnHold = (!MediaSession.HasVideo) ? null : new VideoOptions
                {
                    VideoSource           = VideoSourcesEnum.TestPattern,
                    SourceFile            = RtpAVSession.VIDEO_ONHOLD_TESTPATTERN,
                    SourceFramesPerSecond = VIDEO_ONHOLD_FRAMES_PER_SECOND
                };
                await(MediaSession as RtpAVSession).SetSources(audioOnHold, videoOnHold);
            }

            // At this point we could stop listening to the remote party's RTP and play something
            // else and also stop sending our microphone output and play some music.
            StatusMessage(this, "Local party put on hold");
        }
Esempio n. 4
0
        static void Main()
        {
            Console.WriteLine("SIPSorcery Call Hold and Blind Transfer example.");
            Console.WriteLine("Press 'c' to initiate a call to the default destination.");
            Console.WriteLine("Press 'h' to place an established call on and off hold.");
            Console.WriteLine("Press 'H' to hangup an established call.");
            Console.WriteLine("Press 't' to request a blind transfer on an established call.");
            Console.WriteLine("Press 'q' or 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.

            Log = AddConsoleLogger();

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

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

            Console.WriteLine($"Listening for incoming calls on: {sipTransport.GetSIPChannels().First().ListeningEndPoint}.");

            EnableTraceLogs(sipTransport);

            var winAudio = new WindowsAudioEndPoint(new AudioEncoder());

            winAudio.RestrictCodecs(new List <AudioCodecsEnum> {
                AudioCodecsEnum.PCMU
            });

            // 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, true);

            userAgent.RemotePutOnHold   += () => Log.LogInformation("Remote call party has placed us on hold.");
            userAgent.RemoteTookOffHold += () => Log.LogInformation("Remote call party took us off hold.");
            userAgent.OnIncomingCall    += async(ua, req) =>
            {
                Log.LogInformation($"Incoming call from {req.Header.From.FriendlyDescription()} at {req.RemoteSIPEndPoint}.");
                var uas = userAgent.AcceptCall(req);

                if (userAgent?.IsCallActive == true)
                {
                    // If we are already on a call return a busy response.
                    Log.LogWarning($"Busy response returned for incoming call request.");
                    uas.Reject(SIPResponseStatusCodesEnum.BusyHere, null);
                }
                else
                {
                    var voipSession = new VoIPMediaSession(winAudio.ToMediaEndPoints());
                    voipSession.AcceptRtpFromAny = true;
                    var answerResult = await userAgent.Answer(uas, voipSession);
                }
            };

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

                        if (keyProps.KeyChar == 'c')
                        {
                            if (!userAgent.IsCallActive)
                            {
                                var voipSession = new VoIPMediaSession(winAudio.ToMediaEndPoints());
                                voipSession.AcceptRtpFromAny = true;
                                bool callResult = await userAgent.Call(DEFAULT_DESTINATION_SIP_URI, SIP_USERNAME, SIP_PASSWORD, voipSession);

                                Log.LogInformation($"Call attempt {((callResult) ? "successfull" : "failed")}.");
                            }
                            else
                            {
                                Log.LogWarning("There is already an active call.");
                            }
                        }
                        else if (keyProps.KeyChar == 'h')
                        {
                            // Place call on/off hold.
                            if (userAgent.IsCallActive)
                            {
                                if (userAgent.IsOnLocalHold)
                                {
                                    Log.LogInformation("Taking the remote call party off hold.");
                                    (userAgent.MediaSession as VoIPMediaSession).TakeOffHold();
                                    userAgent.TakeOffHold();
                                }
                                else
                                {
                                    Log.LogInformation("Placing the remote call party on hold.");
                                    await(userAgent.MediaSession as VoIPMediaSession).PutOnHold();
                                    userAgent.PutOnHold();
                                }
                            }
                            else
                            {
                                Log.LogWarning("There is no active call to put on hold.");
                            }
                        }
                        else if (keyProps.KeyChar == 'H')
                        {
                            if (userAgent.IsCallActive)
                            {
                                Log.LogInformation("Hanging up call.");
                                userAgent.Hangup();
                            }
                        }
                        else if (keyProps.KeyChar == 't')
                        {
                            // Initiate a blind transfer to the remote call party.
                            if (userAgent.IsCallActive)
                            {
                                var transferURI = SIPURI.ParseSIPURI(TRANSFER_DESTINATION_SIP_URI);
                                bool result     = await userAgent.BlindTransfer(transferURI, TimeSpan.FromSeconds(TRANSFER_TIMEOUT_SECONDS), exitCts.Token);
                                if (result)
                                {
                                    // If the transfer was accepted the original call will already have been hungup.
                                    // Wait a second for the transfer NOTIFY request to arrive.
                                    await Task.Delay(1000);
                                    exitCts.Cancel();
                                }
                                else
                                {
                                    Log.LogWarning($"Transfer to {TRANSFER_DESTINATION_SIP_URI} failed.");
                                }
                            }
                            else
                            {
                                Log.LogWarning("There is no active call to transfer.");
                            }
                        }
                        else if (keyProps.KeyChar == 'q')
                        {
                            // Quit application.
                            exitCts.Cancel();
                        }
                    }
                }
                catch (Exception excp)
                {
                    Log.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...");

            if (userAgent != null)
            {
                if (userAgent.IsCallActive)
                {
                    Log.LogInformation($"Hanging up call to {userAgent?.CallDescriptor?.To}.");
                    userAgent.Hangup();
                }

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

            #endregion
        }
Esempio n. 5
0
        static void Main()
        {
            Console.WriteLine("SIPSorcery Call Hold and Blind Transfer example.");
            Console.WriteLine("Press 'c' to initiate a call to the default destination.");
            Console.WriteLine("Press 'h' to place an established call on and off hold.");
            Console.WriteLine("Press 'H' to hangup an established call.");
            Console.WriteLine("Press 't' to request a blind transfer on an established call.");
            Console.WriteLine("Press 'q' or 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.

            AddConsoleLogger();

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

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

            Console.WriteLine($"Listening for incoming calls on: {sipTransport.GetSIPChannels().First().ListeningEndPoint}.");

            EnableTraceLogs(sipTransport);

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

            RtpAVSession rtpAVSession = null;

            // 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.RemotePutOnHold   += () => Log.LogInformation("Remote call party has placed us on hold.");
            userAgent.RemoteTookOffHold += () => Log.LogInformation("Remote call party took us off hold.");

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

                        rtpAVSession = new RtpAVSession(new AudioOptions {
                            AudioSource = AudioSourcesEnum.CaptureDevice
                        }, null);
                        await userAgent.Answer(incomingCall, rtpAVSession);

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

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

                        if (keyProps.KeyChar == 'c')
                        {
                            if (!userAgent.IsCallActive)
                            {
                                rtpAVSession = new RtpAVSession(new AudioOptions {
                                    AudioSource = AudioSourcesEnum.CaptureDevice
                                }, null);
                                bool callResult = await userAgent.Call(DEFAULT_DESTINATION_SIP_URI, SIP_USERNAME, SIP_PASSWORD, rtpAVSession);

                                Log.LogInformation($"Call attempt {((callResult) ? "successfull" : "failed")}.");
                            }
                            else
                            {
                                Log.LogWarning("There is already an active call.");
                            }
                        }
                        else if (keyProps.KeyChar == 'h')
                        {
                            // Place call on/off hold.
                            if (userAgent.IsCallActive)
                            {
                                if (userAgent.IsOnLocalHold)
                                {
                                    Log.LogInformation("Taking the remote call party off hold.");
                                    userAgent.TakeOffHold();
                                    await(userAgent.MediaSession as RtpAVSession).SetSources(new AudioOptions {
                                        AudioSource = AudioSourcesEnum.CaptureDevice
                                    }, null);
                                }
                                else
                                {
                                    Log.LogInformation("Placing the remote call party on hold.");
                                    userAgent.PutOnHold();
                                    await(userAgent.MediaSession as RtpAVSession).SetSources(new AudioOptions
                                    {
                                        AudioSource = AudioSourcesEnum.Music,
                                        SourceFiles = new Dictionary <SDPMediaFormatsEnum, string>
                                        {
                                            { SDPMediaFormatsEnum.PCMU, _currentDir + "/" + AUDIO_FILE_PCMU }
                                        }
                                    }, null);
                                }
                            }
                            else
                            {
                                Log.LogWarning("There is no active call to put on hold.");
                            }
                        }
                        else if (keyProps.KeyChar == 'H')
                        {
                            if (userAgent.IsCallActive)
                            {
                                Log.LogInformation("Hanging up call.");
                                userAgent.Hangup();
                            }
                        }
                        else if (keyProps.KeyChar == 't')
                        {
                            // Initiate a blind transfer to the remote call party.
                            if (userAgent.IsCallActive)
                            {
                                var transferURI = SIPURI.ParseSIPURI(TRANSFER_DESTINATION_SIP_URI);
                                bool result     = await userAgent.BlindTransfer(transferURI, TimeSpan.FromSeconds(TRANSFER_TIMEOUT_SECONDS), exitCts.Token);
                                if (result)
                                {
                                    // If the transfer was accepted the original call will already have been hungup.
                                    // Wait a second for the transfer NOTIFY request to arrive.
                                    await Task.Delay(1000);
                                    exitCts.Cancel();
                                }
                                else
                                {
                                    Log.LogWarning($"Transfer to {TRANSFER_DESTINATION_SIP_URI} failed.");
                                }
                            }
                            else
                            {
                                Log.LogWarning("There is no active call to transfer.");
                            }
                        }
                        else if (keyProps.KeyChar == 'q')
                        {
                            // Quit application.
                            exitCts.Cancel();
                        }
                    }
                }
                catch (Exception excp)
                {
                    SIPSorcery.Sys.Log.Logger.LogError($"Exception Key Press listener. {excp.Message}.");
                }
            });

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

            rtpAVSession?.Close("app exit");

            if (userAgent != null)
            {
                if (userAgent.IsCallActive)
                {
                    Log.LogInformation($"Hanging up call to {userAgent?.CallDescriptor?.To}.");
                    userAgent.Hangup();
                }

                // 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
        }
Esempio n. 6
0
 /// <summary>
 /// Puts the remote call party on hold.
 /// </summary>
 public void PutOnHold()
 {
     MediaSession.PutOnHold();
     m_userAgent.PutOnHold();
     StatusMessage(this, "Local party put on hold");
 }
Esempio n. 7
0
        /// <summary>
        /// Process user key presses.
        /// </summary>
        /// <param name="exit">The cancellation token to set if the user requests to quit the application.</param>
        private static void OnKeyPress(CancellationTokenSource exitCts)
        {
            try
            {
                while (!exitCts.IsCancellationRequested)
                {
                    var keyProps = Console.ReadKey();

                    if (keyProps.KeyChar == 'c')
                    {
                        if (_ua != null)
                        {
                            Log.LogWarning($"An existing call is already in progress.");
                        }
                        else
                        {
                            _ua = new SIPUserAgent(_sipTransport, null);

                            // Place an outgoing call.
                            _ua.ClientCallTrying   += (uac, resp) => Log.LogInformation($"{uac.CallDescriptor.To} Trying: {resp.StatusCode} {resp.ReasonPhrase}.");
                            _ua.ClientCallRinging  += (uac, resp) => Log.LogInformation($"{uac.CallDescriptor.To} Ringing: {resp.StatusCode} {resp.ReasonPhrase}.");
                            _ua.ClientCallFailed   += (uac, err, resp) => Log.LogWarning($"{uac.CallDescriptor.To} Failed: {err}, Status code: {resp?.StatusCode}");
                            _ua.ClientCallAnswered += (uac, resp) => Log.LogInformation($"{uac.CallDescriptor.To} Answered: {resp.StatusCode} {resp.ReasonPhrase}.");
                            _ua.OnDtmfTone         += (key, duration) => Log.LogInformation($"Received DTMF tone {key}.");
                            //ua.OnRtpEvent += (evt, hdr) => Log.LogDebug($"transferee rtp event {evt.EventID}, ssrc {hdr.SyncSource}, duration {evt.Duration}, end of event {evt.EndOfEvent}, timestamp {hdr.Timestamp}, marker {hdr.MarkerBit}.");
                            _ua.OnCallHungup += (dialog) => Log.LogDebug("Call hungup by remote party.");

                            Task.Run(async() =>
                            {
                                var rtpSession = CreateRtpSession();
                                var callResult = await _ua.Call(CALLEE_DST, null, null, rtpSession);

                                if (!callResult)
                                {
                                    Log.LogWarning($"Call to {CALLEE_DST} failed.");
                                }
                                else
                                {
                                    Log.LogInformation($"Call to {CALLEE_DST} was successful.");
                                }
                            });
                        }
                    }
                    else if (keyProps.KeyChar == 'h')
                    {
                        if (_ua != null)
                        {
                            if (_ua.IsOnLocalHold)
                            {
                                Log.LogDebug("Taking callee off hold.");
                                _ua.TakeOffHold();
                            }
                            else
                            {
                                Log.LogDebug("Placing callee on hold.");
                                _ua.PutOnHold();
                            }
                        }
                        else
                        {
                            Log.LogDebug("No active call to place on hold.");
                        }
                    }
                    else if (keyProps.KeyChar == 'b')
                    {
                        if (_ua != null)
                        {
                            Log.LogDebug("Hanging up call.");
                            _ua.Hangup();
                        }
                        else
                        {
                            Log.LogDebug("No active call to hangup.");
                        }

                        Task.Delay(1000).Wait();

                        _ua = null;
                    }
                    else if (keyProps.KeyChar == 'a')
                    {
                        Log.LogDebug($"Yes I am alive!");
                    }
                    else if (keyProps.KeyChar == 'q')
                    {
                        // Quit application.
                        Log.LogInformation("Quitting");
                        exitCts.Cancel();
                        break;
                    }
                }
            }
            catch (Exception excp)
            {
                Log.LogError($"Exception OnKeyPress. {excp.Message}.");
            }
        }