Couldn't detect that call is hung up/Cancelled by the user in SIPSorcery C#

235 Views Asked by At

I am developing VOIP application in MAUI using SIPSorcery v6.0.12.

I am having below status in mentioned cases.

  1. The user1 calls user2, The user2 doesn't accepts call and declines it : Success
  2. The user1 calls user2, The user2 doesn't accepts call and The user1 cancel call : Success
  3. The user1 calls user2, The user2 accepts call and declines it : Failed
  4. The user1 calls user2, The user2 accepts call and The user1 cancel call : Failed

In 3rd & 4th case, The party is not able to detect that another party has hung-up the call.

call-dialer.xaml.cs (The user1 places the call)

using SIPSorcery.Media;
using SIPSorcery.SIP.App;
using SIPSorceryMedia.Windows;
using sipsorcery.desktop.preferences_utilities;
using Serilog;
using SIPSorcery.SIP;
using System.Net;

namespace sipsorcery.desktop;

public partial class call_dialer : ContentPage
{
    private string gblStrDomain = "@server.com";
    private string gblStrCloudDestinationAddress = "[email protected]";
    private string gblStrExtentionNumber = "", gblStrExtentionPassword = "";

    SIPUserAgent objSIPUserAgent = null;
    SIPRequest objSIPRequest = null;
    SIPServerUserAgent objSIPServerUserAgent = null;
    SIPTransport objSIPTransport = null;

    ILogger objLogger = Log.ForContext<call_dialer>();

    public call_dialer()
    {
        InitializeComponent();
        //GLOBAL VARIABLES SET HERE
    }

    #region EVENTS
    /// <summary>
    /// THIS EVENT IS CALLED ON CLICK OF 'PLACE CALL' BUTTON
    /// </summary>
    /// <param name="objSender"></param>
    /// <param name="objEventArgs"></param>
    private async void btnCall_Clicked(object objSender, EventArgs objEventArgs)
    {
        try
        {
            string strDialledNumber = !string.IsNullOrEmpty(entryCallNumber.Text) ? entryCallNumber.Text : "";
            if (!string.IsNullOrEmpty(strDialledNumber))
            {
                if (gblStrExtentionNumber == strDialledNumber)
                {
                    objLogger.Information($"Couldn't place call on {strDialledNumber}.");
                    await DisplayAlert("Warning", $"Couldn't place call on {strDialledNumber}.", "OK");
                }
                else
                {
                    //PLACE THE CALL AND WAIT FOR THE RESULT
                    objSIPUserAgent = new SIPUserAgent();
                    WindowsAudioEndPoint objWindowsAudioEndPoint = new WindowsAudioEndPoint(new AudioEncoder());
                    VoIPMediaSession objVoIPMediaSession = new VoIPMediaSession(objWindowsAudioEndPoint.ToMediaEndPoints());
                    objVoIPMediaSession.AcceptRtpFromAny = true;

                    objLogger.Information($"SIPUserAgent,WindowsAudioEndPoint,VoIPMediaSession instance created to place a call");

                    #region CALLING EVENTS
                    objSIPUserAgent.ClientCallRinging += async (isip_client_user_agent, sip_response) =>
                    {
                        objLogger.Information($"Client call is ringing");
                        Device.InvokeOnMainThreadAsync(() =>
                        {
                            ShowGrid("gridRinging");
                        });
                    };
                    objSIPUserAgent.ClientCallTrying += async (isip_client_user_agent, sip_response) =>
                    {
                        objLogger.Information($"Trying to connect call");
                        Device.InvokeOnMainThreadAsync(() =>
                        {
                            ShowGrid("gridRinging");
                        });
                    };
                    objSIPUserAgent.ClientCallAnswered += async (isip_client_user_agent, sip_response) =>
                    {
                        objLogger.Information($"Call is accepted by client machine");
                        Device.InvokeOnMainThreadAsync(() =>
                        {
                            ShowGrid("gridCalling");
                        });
                    };
                    objSIPUserAgent.ClientCallFailed += async (isip_client_user_agent, error_response, sip_response) =>
                    {
                        objLogger.Information($"Client call is failed");
                        Device.InvokeOnMainThreadAsync(() =>
                        {
                            ShowGrid("gridCallDialer");
                        });
                    };
                    objSIPUserAgent.ServerCallCancelled += async (isip_client_user_agent) =>
                    {
                        objLogger.Information($"Server canclled call");
                        Device.InvokeOnMainThreadAsync(() =>
                        {
                            ShowGrid("gridCallDialer");
                        });
                    };
                    objSIPUserAgent.ServerCallRingTimeout += async (isip_client_user_agent) =>
                    {
                        objLogger.Information($"Ringing timeout");
                        Device.InvokeOnMainThreadAsync(() =>
                        {
                            ShowGrid("gridCallDialer");
                        });
                    };
                    objSIPUserAgent.OnCallHungup += async (sip_dialogue) =>
                    {
                        objLogger.Information($"Call is hanging up");
                        Device.InvokeOnMainThreadAsync(() =>
                        {
                            ShowGrid("gridCallDialer");
                        });
                    };
                    #endregion

                    string strDestinationAddress = strDialledNumber + gblStrDomain;

                    bool blnCallResult = await objSIPUserAgent.Call(strDestinationAddress, gblStrExtentionNumber, gblStrExtentionPassword, objVoIPMediaSession);
                }
            }
        }
        catch
        {
        }
    }

    /// <summary>
    /// WHEN USER1 PLACES CALL, 'CANCEL' CALL BUTTON WILL BE SHOWN TO HIM & THIS EVENT IS CALLED ON CLICK OF THAT BUTTON
    /// </summary>
    /// <param name="objSender"></param>
    /// <param name="objEventArgs"></param>
    private async void btnCancelCall_Clicked(object objSender, EventArgs objEventArgs)
    {
        try
        {
            objLogger.Information($"Sender clicked decline");
            if (objSIPUserAgent != null)
            {
                objSIPUserAgent.Hangup();
                objLogger.Information($"objSIPUserAgent.Hangup() method is called from server machine");

                objSIPUserAgent.Cancel();
                objLogger.Information($"objSIPUserAgent.Cancel() method is called from server machine");

                objSIPUserAgent.Dispose();
                objLogger.Information($"objSIPUserAgent.Dispose() method is called from server machine");
            }
            App.Current.MainPage = new call_dialer();
        }
        catch
        {
            App.Current.MainPage = new call_dialer();
        }
    }

    /// <summary>
    /// THIS METHOD IS CALLED WHEN WINDOW IS LOADED/APPEARED
    /// </summary>
    protected override async void OnAppearing()
    {
        base.OnAppearing();
        await Task.Delay(500);
        await Task.Run(() =>
        {
            Device.InvokeOnMainThreadAsync(() =>
            {
                entryCallNumber.Focus();
            });
        });
    }
    #endregion
}

App.xaml.cs (The incoming call events is handled in this file for the user2)

public partial class App : Application
{
    public App()
    {
        InitializeComponent();

        SIPTransport objSIPTransport = new SIPTransport();

        objSIPTransport.AddSIPChannel(new SIPTCPChannel(new IPEndPoint(IPAddress.Any, 5060)));

        SIPUserAgent objSIPUserAgent = new SIPUserAgent(objSIPTransport, null, true);

        objSIPUserAgent.OnIncomingCall += async (useragent, siprequest) =>
        {
            Device.InvokeOnMainThreadAsync(() =>
            {
                MainPage = new incoming_call_notification(siprequest, useragent, objSIPTransport);
            });
        };

        if (new preferences_management().ValidUser(objSIPTransport))
        {
            MainPage = new call_dialer();
        }
        else
        {
            MainPage = new user_login();
        }
    }
}

incoming-call-notification.xaml.cs (When the incoming call event is handled for the user2, He will get 'Accept' & 'Reject' button)

using SIPSorcery.Media;
using SIPSorcery.SIP;
using SIPSorcery.SIP.App;
using SIPSorceryMedia.Windows;
using Serilog;

namespace sipsorcery.desktop;

public partial class incoming_call_notification : ContentPage
{
    SIPRequest objSIPRequest = null;
    SIPUserAgent objSIPUserAgent = null;
    SIPServerUserAgent objSIPServerUserAgent = null;
    SIPTransport objSIPTransport = null;

    public incoming_call_notification(SIPRequest _objSIPRequest, SIPUserAgent _objSIPUserAgent, SIPTransport _objSIPTransport)
    {
        InitializeComponent();
        objSIPRequest = _objSIPRequest;
        objSIPUserAgent = _objSIPUserAgent;
        objSIPTransport = _objSIPTransport;
    }

    #region METHODS
    /// <summary>
    /// THIS METHOD IS USED TO START TIMER WHEN CALL IS CONNECTED
    /// </summary>
    private void StartCallingTimer()
    {
        DateTime objCurrentDateTime = DateTime.Now;
        IDispatcherTimer _objIDispatcherTimer;
        _objIDispatcherTimer = Dispatcher.CreateTimer();
        _objIDispatcherTimer.Interval = TimeSpan.FromMilliseconds(1000);
        _objIDispatcherTimer.Tick += (start, end) =>
        {
            lblCallTime.Text = string.Format("{0:00}:{1:00}:{2:00}", (DateTime.Now - objCurrentDateTime).Hours, (DateTime.Now - objCurrentDateTime).Minutes, (DateTime.Now - objCurrentDateTime).Seconds);
        };
        _objIDispatcherTimer.Start();
    }

    /// <summary>
    /// THIS METHOD IS USED TO SHOW GRID BY NAME
    /// </summary>
    /// <param name="strGridName"></param>
    private void ShowGrid(string strGridName)
    {
        try
        {
            if (!string.IsNullOrEmpty(strGridName))
            {
                if (strGridName == "gridIncomingCall")
                {
                    gridIncomingCall.IsVisible = true;
                    gridCallAccepted.IsVisible = false;
                }
                else if (strGridName == "gridCallAccepted")
                {
                    gridCallAccepted.IsVisible = true;
                    gridIncomingCall.IsVisible = false;
                    StartCallingTimer();
                }
            }
        }
        catch
        {
        }
    }
    #endregion

    #region EVENTS
    /// <summary>
    /// THE USER2 WILL GET ACCEPT & REJECT BUTTON WHEN CALL IS INCOMING. BY CLICKING ON ACCEPT BUTTON, THIS EVENT IS CALLED
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private async void btnAccept_Clicked(object sender, EventArgs e)
    {
        try
        {
            if (objSIPRequest != null && objSIPUserAgent != null)
            {
                objSIPServerUserAgent = objSIPUserAgent.AcceptCall(objSIPRequest);
                WindowsAudioEndPoint objWindowsAudioEndPoint = new WindowsAudioEndPoint(new AudioEncoder());
                VoIPMediaSession objVoIPMediaSession = new VoIPMediaSession(objWindowsAudioEndPoint.ToMediaEndPoints());
                objVoIPMediaSession.AcceptRtpFromAny = true;

                objSIPUserAgent.ClientCallRinging += async (isip_client_user_agent, sip_response) =>
                {
                    Device.InvokeOnMainThreadAsync(() =>
                    {
                        ShowGrid("gridIncomingCall");
                    });
                };
                objSIPUserAgent.ClientCallTrying += async (isip_client_user_agent, sip_response) =>
                {
                    Device.InvokeOnMainThreadAsync(() =>
                    {
                        ShowGrid("gridIncomingCall");
                    });
                };
                objSIPUserAgent.ClientCallAnswered += async (isip_client_user_agent, sip_response) =>
                {
                    Device.InvokeOnMainThreadAsync(() =>
                    {
                        ShowGrid("gridCallAccepted");
                    });
                };
                objSIPUserAgent.ClientCallFailed += async (isip_client_user_agent, error_response, sip_response) =>
                {
                    Device.InvokeOnMainThreadAsync(() =>
                    {
                        App.Current.MainPage = new call_dialer();
                    });
                };
                objSIPUserAgent.ServerCallCancelled += async (isip_client_user_agent) =>
                {
                    Device.InvokeOnMainThreadAsync(() =>
                    {
                        App.Current.MainPage = new call_dialer();
                    });
                };
                objSIPUserAgent.ServerCallRingTimeout += async (isip_client_user_agent) =>
                {
                    Device.InvokeOnMainThreadAsync(() =>
                    {
                        App.Current.MainPage = new call_dialer();
                    });
                };
                objSIPUserAgent.OnCallHungup += async (sip_dialogue) =>
                {
                    Device.InvokeOnMainThreadAsync(() =>
                    {
                        App.Current.MainPage = new call_dialer();
                    });
                };
                objSIPServerUserAgent.CallCancelled += async (isip_client_user_agent) =>
                {
                    Device.InvokeOnMainThreadAsync(() =>
                    {
                        App.Current.MainPage = new call_dialer();
                    });
                };

                await objSIPUserAgent.Answer(objSIPServerUserAgent, objVoIPMediaSession);

                ShowGrid("gridCallAccepted");
            }
        }
        catch
        {
        }
    }

    /// <summary>
    /// THE USER2 WILL GET ACCEPT & REJECT BUTTON WHEN CALL IS INCOMING. BY CLICKING ON REJECT BUTTON, THIS EVENT IS CALLED
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void btnDecline_Clicked(object sender, EventArgs e)
    {
        try
        {
            if (objSIPServerUserAgent == null)
            {
                objSIPServerUserAgent = objSIPUserAgent.AcceptCall(objSIPRequest);
            }
            objSIPServerUserAgent.Reject(SIPResponseStatusCodesEnum.Decline, null);
            
            #region ALSO USED BELOW TWO CODE SNIPPETS BUT DIDN'T WORKED
            //if (objSIPTransport != null)
            //{
            //    SIPClientUserAgent objClientUserAgent = new SIPClientUserAgent(objSIPTransport);
            //    objClientUserAgent.Hangup();
            //    objClientUserAgent.Cancel();
            //}
            //if(objSIPUserAgent != null)
            //{
            //  objSIPUserAgent.Hangup();
            //    objSIPUserAgent.Cancel();
            //  objSIPUserAgent.Dispose();
            //}
            #endregion
            
            App.Current.MainPage = new call_dialer();
        }
        catch
        {
            App.Current.MainPage = new call_dialer();
        }
    }
    #endregion
}

I am getting failure in below two cases.

  1. When the user1 calls the user2, The user2 accepted the call & The user1 hungup call. In this case, The user2 is not able to detect any event or acknowledgement that the user1 has hungup the call.
  2. When the user1 calls the user2, The user2 accepted the call & The user2 hungup the call. In this case, The user1 is not able to detect any event or acknowledgement that the user2 has hungup the call.
0

There are 0 best solutions below