ladendirekt / pjsip4net

A wrapper library exposing the pjsip library to the .NET world in a OO-friendly way.
71 stars 42 forks source link

slow disconnect event #41

Open marknelissen opened 8 years ago

marknelissen commented 8 years ago

When we have an incoming call, and the caller hangs up before we answer, it takes almost a minute before the status changes, or the ring event is thrown. This issue seems not related to the sip server used, since we don't have the issue with the same accounts used through microsip, which is also based on pjsip. Is there any configuration we can add to speed up detection of the caller hanging up?

siniypin commented 8 years ago

It looks like your caller user agent does not receive Hangup message and expires a call session after a timeout, which equals exactly one minute by default. Therefore, to understand where the problem is, you'd have to analyse caller's and callee's SIP traffic. In order to capture sent and received SIP messages in your log you can set pjsip4net "log messages" config property to true. Also set a "log level" property to 5 to get the most detailed dump. You can configure these properties either in .cfg file https://gist.github.com/siniypin/7860029#file-app-config-L6 or with code configuration Configure.Pjsip4Net().With(x => x.LoggingConfig. LogMessages = true)

marhnix commented 8 years ago

log.txt

2016-01-20 11:00:11,583 -> an incoming call is sent and 2 sec later the caller hangs up

Only 30 sec later a CANCEL request is sent 2016-01-20 11:00:43,490 root [3] DEBUG - 11:00:43.490 pjsua_core.c RX 458 bytes Request msg CANCEL/cseq=1567479372 (rdata0841A00C) from UDP 10.1.20.7:5060: CANCEL sip:101@10.1.20.149:5060 SIP/2.0

marknelissen commented 8 years ago

Some additional information: this only happens when the call has not been answered. In case the callee answers the call, when the caller hangs up, it immediately disconnects.

Other piece of information, which I do not know is relevant to this issue: we had to put the registration timeout for the account at something like 3000 in order for the registration to function. Otherwise we get messages like:

2016-01-20 10:48:47,687 root [3] WARN  -  10:48:47.687    pjsua_acc.c  SIP registration failed, status=423 (Registration Too Brief)

2016-01-20 10:48:47,689 pjsip4net.Accounts.TimedOutAccountRegistrationState [3] DEBUG - Account 1 UnknownStatusState
2016-01-20 10:48:47,689 pjsip4net.Accounts.TimedOutAccountRegistrationState [3] DEBUG - Interval Too Brief
siniypin commented 8 years ago

I assume this is a callee's log you sent. What I see is:

Unfortunately this log alone is not enough to understand where the problem is. The client seem to behave correctly as it reacts on commands received as it should (see a cancellation scenario sequence: http://www.in2eps.com/fo-sip/pdf/Ti-SIP-3665-3.8.pdf) Can you record a caller and a registrar server invite session log as well? To check that the client behaves right, you can try to call from a client on 10.xx.xx.157 to your callee on 10.xx.xx.149 directly (using a default local account, not the one from registrar server) and cancel a call before it was picked up. I expect the caller to hangup a call immediately.

marknelissen commented 8 years ago

registration.txt This is the log of the registration sequence. I don't know if that was what you meant with registrar server invite session?

I don't seem to be able to perform direct call without passing through the registrar server. Here are the caller.txt and callee.txt parallel logs, where you can see 7s on the caller side between starting call and hang up, and on the callee side more than 30s between the same signals appearing in the logs. This does not happen when the callee is a microsip client, where the hangup is received immediately, which makes me think it might be related to the client configuration.

This is the app.config configuration part:

<sipua srtp="Disabled" secureSignaling="0" logMessages="true" logLevel="5" traceAndDebug="false" autoAnswer="false" autoConference="false" maxCalls="1">
    <accounts>
    </accounts>
    <sipTransport type="udp" Port="5060" />
    <networkSettings natInSDP="true" forceLooseRoute="false">
      <turn enabled="false" server="" type="udp" userName="" password="" realm="" />
      <ice enabled="true" noRTCP="false" />
    </networkSettings>
    <media isVADEnabled="true" captureDeviceId="1" playbackDeviceId="2" />
  </sipua>

And this is the code part:

sipServer = Configuration.SipServer;
if (sipServer != null)
{
    sipUserAgent = Configure.Pjsip4Net().FromConfig().Build().Start();
    IAccount account = sipUserAgent.AccountManager.Register(x =>
    {
        x.WithExtension(Configuration.SipExtension).At(sipServer);
        var port = Configuration.SipPort;
        if (port != null)
        {
            x.Through(port);
        }
        var registrationTimeout = Configuration.SipRegistrationTimeout;
        if (registrationTimeout != null)
        {
            x.WithRegistrationTimeout((uint)registrationTimeout);
        }
        var password = Configuration.SipPassword;
        if (password != null)
        {
            x.WithPassword(password);
        }
        return x.Default().Register();
    });
    sipUserAgent.CallManager.IncomingCall += CallManager_IncomingCall;
    sipUserAgent.CallManager.CallStateChanged += CallManager_CallStateChanged;
    sipUserAgent.CallManager.Ring += CallManager_Ring;
}

where config is a custom class that provides access to the registry values, of which the important one is the registration timeout which is currently set at 3000. The only differences in configuration between the caller and callee configuration are in the device ids for the input and output, since they don't have the same number of devices. They are running the same software and OS.

siniypin commented 8 years ago

Please try the same scenario with ICE disabled. You don't seem to have a complex network topology between your clients, you don't need ICE at first place.

<ice enabled="false" noRTCP="false" />

Best regards, Boris Tveritnev de.linkedin.com/pub/boris-tveritnev/11/3a4/113/ www.xing.com/profile/Boris_Tveritnev

On 20 January 2016 at 18:01, marknelissen notifications@github.com wrote:

registration.txt https://github.com/siniypin/pjsip4net/files/97734/registration.txt This is the log of the registration sequence. I don't know if that was what you meant with registrar server invite session?

I don't seem to be able to perform direct call without passing through the registrar server. Here are the caller.txt https://github.com/siniypin/pjsip4net/files/97747/caller.txt and callee.txt https://github.com/siniypin/pjsip4net/files/97748/callee.txt parallel logs, where you can see 7s on the caller side between starting call and hang up, and on the callee side more than 30s between the same signals appearing in the logs. This does not happen when the callee is a microsip client, where the hangup is received immediately, which makes me think it might be related to the client configuration.

This is the app.config configuration part:

<sipua srtp="Disabled" secureSignaling="0" logMessages="true" logLevel="5" traceAndDebug="false" autoAnswer="false" autoConference="false" maxCal ls="1">

<sipTransport type="udp" Port="5060" />
<networkSettings natInSDP="true" forceLooseRoute="false">
  <turn enabled="false" server="" type="udp" userName="" password="" realm="" />
  <ice enabled="true" noRTCP="false" />
</networkSettings>
<media isVADEnabled="true" captureDeviceId="1" playbackDeviceId="2" />

And this is the code part:

sipServer = Configuration.SipServer;if (sipServer != null) { sipUserAgent = Configure.Pjsip4Net().FromConfig().Build().Start(); IAccount account = sipUserAgent.AccountManager.Register(x => { x.WithExtension(Configuration.SipExtension).At(sipServer); var port = Configuration.SipPort; if (port != null) { x.Through(port); } var registrationTimeout = Configuration.SipRegistrationTimeout; if (registrationTimeout != null) { x.WithRegistrationTimeout((uint)registrationTimeout); } var password = Configuration.SipPassword; if (password != null) { x.WithPassword(password); } return x.Default().Register(); }); sipUserAgent.CallManager.IncomingCall += CallManager_IncomingCall; sipUserAgent.CallManager.CallStateChanged += CallManager_CallStateChanged; sipUserAgent.CallManager.Ring += CallManager_Ring; }

where config is a custom class that provides access to the registry values, of which the important one is the registration timeout which is currently set at 3000.

— Reply to this email directly or view it on GitHub https://github.com/siniypin/pjsip4net/issues/41#issuecomment-173274227.

marknelissen commented 8 years ago

We can indeed disable the ice, thank you for the tip. Unfortunately, this does not affect the issue.

siniypin commented 8 years ago

Hi Mark, did you manage to solve your issue? I think the difference in server response was caused by a provisional 100 Trying response from a client. Normally it would reply with 180 Ringing.

marknelissen commented 8 years ago

Hi, no, we still are having the issue. I'm not very at home in SIP protocol, and as such, I don't entirely understand your last comment. Does it mean the caller is sending the wrong event, or is the callee wrongly reacting on the events?

siniypin commented 8 years ago

The callee does not react 100% correct. The response it provides is valid, but it isn't complete.

marknelissen commented 8 years ago

How can this be corrected? Does the library need to be updated or is it something to be corrected on configuration or api use level?

marknelissen commented 8 years ago

I have been able to confirm the cause and fix it by sending the ringing event to the incoming call. Thanks to your information, I have been able to avoid this issue when upgrading to the 2.4.5 version of pjsip, by sending back the correct event to the incoming call.

I never figured out how to correct the issue on the application level, without changing the wrapper. This might be a feature to look into, on the onRing event. I'll not close the issue, since it can serve as base for the new feature. I'll let you decide how you want to track it. If you don't need this thread for the tracking, feel free to close the discussion, since for me the issue has been solved.

Thank you for your great help. Not sure I would have been able to get the application up as fast without it.

siniypin commented 8 years ago

Hey Mark,

happy to help you. I'll happily extend pjsip4net to support the feature you missed. Could you elaborate on that? What event did you have to send manually in order to resolve the issue?

Cheers

marknelissen commented 8 years ago

Like you indicated, the client was not sending the ringing response to the caller. I executed the following code to handle playing the ringing sound

private void CallManager_Ring(object sender, RingEventArgs e)
        {
            if (e.RingOn && !e.IsRingback)
            {
                wplayer.controls.play();
            }
            else
            {
                wplayer.controls.stop();
            }
        }

There should be some callback on the event to signal that you are playing the ringing sound, so as to notify the caller that you are ringing. Or the notification shoud always be send after triggering the ring event.