[Home]

Summary:ASTERISK-09594: Sip doesn't issue re-invite when before bye when hangup is caused by timeout on channel
Reporter:Gaspar Zoltan (gasparz)Labels:
Date Opened:2007-06-05 17:05:13Date Closed:2007-07-11 19:59:11
Priority:MajorRegression?No
Status:Closed/CompleteComponents:Channels/chan_sip/Transfers
Versions:Frequency of
Occurrence
Related
Issues:
Environment:Attachments:( 0) asterisk_sip_rtp_crash.log
( 1) sip_reinvite_failed.txt
Description:Hi,

This is a copy of bug: 0009792: Dial option S and reinvites at applicaton dial-> no response

After looking into the source I came to the following conclusion: When ma_duration is set to a call it somehow doesn't call the same hangup function as the receiving of a bye message. When the call times out the call (that has re-invites) does not issue a re-invite before bye in order to get the rtp back to the server causing the playback of sound or any RTP involving action to be impossible.
Use case: when a client calls in the prepaid sistem he can place the call for x seconds. If the call timed out and had to be interupted we are trying to play back a message telling the client he ran out of money. RTP hadn't been taken back to the asterisk server before the bye was sent to end that channel when the channel timed out, so we can't playback anything => Can't use re-invite.

Thanks,

Below is the original post (0009792: Dial option S and reinvites )


We are trying to setup asterisk to send reinvites and use the max_duration option for Dial (option S). All goes well but when the max_duration is passed after the dial we cannot play any sound:
WARNING[27869]: file.c:587 ast_readaudio_callback: Failed to write frame.


Looking into this issue we found out that when the call is hanguped by asterisk the RTP ip is not taken back to asterisk by another invite, so it makes sence failing to send RTP.

Our testcase:
We use agi for running the applications but I really think this is not affecting the test. The succesion of the applications run for this test is:

Answer
say_number(12)
Dial(Sip/destination@provider||S(5))
say_number(34)
hangup

We captured the sip messages and the callflow is:

Phone -> asterisk: invite
Asteriks - >Phone: 100 Trying
Asteriks - >Phone: 200 OK
Phone -> Asterisk: ACK
(now on the rtp we have the the say_number(12)
Asterisk -> Provider: Invite -> SDP: RTP endpoint Asterisk ip
Provider -> Asterisk: 100 Trying
Provider -> Asterisk: 183 Session
Provider -> Asterisk: 200 OK
Asterisk -> Provider: Ack

Asterisk -> Phone: Invite -> SDP: RTP endpoint Provider ip
Asterisk -> Provider: Invite -> SDP: RTP endpoint Phone ip
Provider -> Asterisk: 100 Trying
Phone -> Asterisk: 200 OK
Asterisk -> Phone: Ack
Provider -> Asterisk: 200 OK
Asterisk -> Provider: Ack
(I assume right now the RTP goes between the phone and the provider on the (newly) negociated codec and have 5 seconds of call)

Asterisk -> Provider: Invite -> SDP: RTP endpoint Phone ip
Provider -> Asterisk: 100 Trying
Provider -> Asterisk: 200 OK
Asterisk -> Provider: Ack
(I didn't understand compleatly why it sent an identical invite the asterisk but it doesn't hurt)

Asterisk -> Provider: bye (the 5 seconds have passed)
Provider -> Asterisk: 200 ok

(I assume now we have the
WARNING[27869]: file.c:587 ast_readaudio_callback: Failed to write frame.)

Asterisk -> Phone : bye
Phone -> Asterisk : Ok


My opinion is that fixing this issue is sending another invite to the phone with SDP: RTP ip address to asterisk if a reinvite had been sent out.
This way the playbacks and any other RTP after the dial can work.

attacked are the actual sip messages.
Comments:By: Jason Parker (jparker) 2007-06-05 17:21:48

Please post your comments on the other bug instead of opening a new one to fix the summary.

By: Gaspar Zoltan (gasparz) 2007-06-05 23:22:59

How can I change the category of the previous one? The problem is in the sip channel driver and not in the dial application.

By: Gaspar Zoltan (gasparz) 2007-06-05 23:31:58

After looking into the source I found that this is sip channel driver problem rather than app_dial.

The app_dial sets the whentohangup property of the channel correctly.
I couldn't find the code part, or the mechanism that is called when this times out, butI found out that when a Sip bye message is received the channel works correctly and sends out an invite, linking back the RTP to the server.

Please comment.

By: Joshua C. Colp (jcolp) 2007-06-06 08:33:12

Fixed in 1.2 as of revision 67649, 1.4 as of revision 67650, and trunk as of revision 67651. Thanks!

By: Gaspar Zoltan (gasparz) 2007-06-07 04:23:47

Hi,

I added the patch found in rtp.c to the 1.2.16 version, rebuilt asterisk and remade the test.

The playback of sound after the bridged call was terminated,because of timeout, is still not working.
Jun  7 04:27:00 WARNING[31665]: file.c:587 ast_readaudio_callback: Failed to write frame

I attached the full sip debug from asterisk, the reinvites before the hangup are showing.

Any idea?

By: Joshua C. Colp (jcolp) 2007-06-07 07:15:37

The attached doesn't actually have any sip debug... and also - I need the exact dialplan logic you are using for this.

By: Gaspar Zoltan (gasparz) 2007-06-07 08:06:59

Sorry about the upload :). I put a wrong file. Now you have the new and good one.

the dial plan is:
Answer
saynumber(123)
dial("SIP/number@provider","S(10)");
saynumber(321)
hangup

Thanks

By: Joshua C. Colp (jcolp) 2007-06-07 08:10:24

You can't play a file in the 'h' extension. Once that extension is executed the call is no longer up.

By: Gaspar Zoltan (gasparz) 2007-06-07 08:34:03

No, we are not playing the file at the h extension.

I removed some lines at line 870 -they vere containing some proprietary info...

After line 869.
   -- AGI Script exec_main.php completed, returning 0
-- Executing DeadAGI("SIP/45e2b8014cddb47a9cfd3cf34d3d6db4-08577918", "exec_hangup.php") in new stack
.....
line 871 ->     -- AGI Script exec_hangup.php completed, returning 0


the actual code is:
$agi->answer();
$agi->say_number("1234");
$agi->exec("dial","SIP/techprefix@provider_ip||S(20)");
sleep(5);
$agi->say_number("4321");
$agi->hangup();
die();

By: Joshua C. Colp (jcolp) 2007-06-07 08:39:18

Once the call is terminated using the S option it is no longer up, you can't do anything with it. That is why this is failing. You are probably going to need to do some modifications to app_dial to get the behavior you want.

By: Gaspar Zoltan (gasparz) 2007-06-07 09:17:00

Playback after a dial if the called party hanged up is possible. We are using it and I don't think this is a question.

In all our tests the called party hanged up first, this should leave the channel between the caller and the server active.

By: Joshua C. Colp (jcolp) 2007-06-07 09:27:36

Yes, if you use the 'g' option. I have just put in a fix that will allow both the 'g' and 'S' option to work when used together, but that doesn't mean that when the  call is hungup because of the timeout of 'S' that it will continue... only when the remote side hangs up will it continue.

By: Gaspar Zoltan (gasparz) 2007-06-08 06:02:27

I made a few tests to try to understand the functionality of DIAL on hangup:

Sip Phone <-> Asterisk <-> SIP Outbound provider

Let's call the channel between SIP Phone and Asterisk INBOUND channel.
Let's call the channel between Asterisk and SIP Outbound provide OUTBOUND channel.

the dial plan actions are:
1 Answer
2 Saynumber 1234
3 Dial(SIP/number@provider_ip||options)
4 saynumber 4321
5 hangup

Test 1) options="" (nothing)
after the called party hanged up the say_number at line 4 was played back correctly

Test 2) options=S(20)
after the called party hanged up the say_number at line 4 was played back correctly

Test 3) options=S(20)
After the timeout the say_nuber at line 4 gave warning and no RTP came

Test 4) options=S(20)g
After the timeout the say_nuber at line 4 gave warning and no RTP came

Test 5) options=L(20000)
after the called party hanged up the say_number at line 4 was played back correctly

Test 6) options=L(20000)
After the timeout the say_nuber at line 4 gave warning and no RTP came

These were the facts. Let's analise a little bit and see what is really confusing for me and I think for a lot of users.

1) when the dial ends in some cases bouth channels are unusable, in some cases the inbound channel still can be used for playback

2) The dial hungs up the inbound channel. This functionality is really unexpected and in almost all cases unwanted. I see only one case where this functionality makes sence: call forward without previous answer:

Dial(SIP/agi_extension@provider_ip)

in this case it would be acceptable to hangup the inbound channel and not ask for a specific hangup instruction

Dial(SIP/agi_extension@provider_ip)
Hangup

3) useing SIP reinvites or not should not affect the algorithm of hanging up calls. This is how it works right now, I just aded this rule here so that there will be no confusion.

How it should work:
There should be a default algorithm for hanging up the inbound channel or not, and an option that overrides this default option.

the default option can be:
Case 1) Always hang up the inbound channel when dial exits with answer
Case 2) Never hang up the inbound channel when dial exists in any of the cases : Answer, Fail, Cancel, Noanswer

The options L,S should only stop the outbound channel, and the inbound channel stop should be guverned by the default functionality + override option

If we take Case 1) options S(20)g should leave the inbound channel open for RTP
and S(20) will hang up the inbound channel too on timeout.

If we take Case 2) option S(20) will not hangup the inbound channel, only the outbound. To achive same functionality we would need to explicitly code this
dial(Sip/....||S(20))
hangup

I don't think anybody wants to hang up the inbound channel when useing S or L options, the point to stop the outgoing channel( I think exclusively for not letting the user to talk over the credit limit).

With the clarification of the cases when the inbound channel is hanged up, the instruction set of asterisk would be an orthogonal one, each asterisk server administrator could control the callflow as he wants, after some clear rules.

Thanks

By: Joshua C. Colp (jcolp) 2007-06-08 07:44:27

Were these actions for your tests executed using an AGI script with DeadAGI?

By: Gaspar Zoltan (gasparz) 2007-06-08 11:19:59

yes, but it shouldn't mater because I put the SIGHUP to ignore.

By: Tilghman Lesher (tilghman) 2007-06-11 08:23:28

DeadAGI will never receive a SIGHUP, as it is designed to ONLY run AFTER a call has hungup.  Please use AGI() for live calls.

By: Gaspar Zoltan (gasparz) 2007-06-12 05:49:34

A changed from DeadAgi to agi and after the call timed out for S(5)g seconds it gave me:

  -- AGI Script Executing Application: (dial) Options: (SIP/number@provider||S(5)g)
   -- Setting call duration limit to 5 seconds.
   -- Called SIP/number@provider
   -- SIP/provider-095dc2c8 is making progress passing it to SIP/45e2b8014cddb47a9cfd3cf34d3d6db4-095d0528
   -- SIP/provider-095dc2c8 answered SIP/45e2b8014cddb47a9cfd3cf34d3d6db4-095d0528
   -- Attempting native bridge of SIP/45e2b8014cddb47a9cfd3cf34d3d6db4-095d0528 and SIP/provider-095dc2c8
Jun 12 06:46:56 WARNING[28728]: res_agi.c:1929 run_agi: No channel, no fd?

By: Joshua C. Colp (jcolp) 2007-06-12 08:32:13

So... as it is - everything is working as it should. That doesn't mean though that it works the way you want/need, you'll probably need to get someone to modify the code. The reason your tests worked as they did is because you were using DeadAGI, which runs on dead/hungup channels. It does not mean however that you should run stuff like Playback and such. The channel you are playing the audio to may be the one that hung up.

By: Gaspar Zoltan (gasparz) 2007-06-12 09:39:56

Ok, I understand, and I realise this toppic had became a more arhitectural discussion than a bug report, you can even call it feature request. The reason why it is working as it is has to do not with the dialplan scripting, the use of deadagi or AGI, it has to do with the cases when a channel is closed. As simple as that.

In the current version of asterisk anyone can see that it is a result of a long developement, where some cases were covered( the cases that made an application to work, a specific use case). This is great, but if asterisk wants a larger share in the VOIP market it has to support greater complexity scripts and cover not just most cases, but all.

My proposal is (sorry about repeating myself sometimes across posts):

Organize by global rules the cases when a channel is hanged up. In the current state, there is a great amount of unknown in this area, each feature comes with different rules, and cannot be used in any context together with other applications.

I don't have the knowledge necessary to modify the asterisk c code, but maybe these ideas will go into a meating where they will be discussed and if they make sence implemented (Adding a new option in the dialplan to have backwords compatibility is fine I think).

Rule 1) The inbound channel can be hanged up only by the Hangup application or the hanging up event of the inbound party

Rule 2) The outbound channel can be hanged up by:
-> Inbound party hanging up
-> Outbound party hanging up
-> A timeout option being set up -> Options L and S from app Dial

Rule 3) All aplications that work with channels can be categorized into:
a) Applications working on the inbound channel: Playback, saynumber, getdigit Do not hang up any channel.
b) Applications for creating/mixing/tieing channels: Dial/conference/Queue
Hang up only the outbound channel that they might created.

Rule 4) The functionality is not conditioned by the way the applications are being called: Dialplan(Realtime or not) or Agi (Deadagi)

Rule 5) Sip reinvites being sent out or not will not effect the hangup of inbound or outbound channels, they will be transparent

Effect 1) An explicit hangup is required for each inbound call
Effect 2) After a dial the inbound channel can always be used (not being conditioned by the outbound channel hangup reason -> kind of logical asumption I think)
Effect 3) Sip reinvites can be sent out in a greater number of cases, optimizeing the codec used and the RTP path of a call. Lower delay and less transcoding, better call quality and lower load on the server, better performace are just some of the reasons why.

Please let me know what do you think about this, pointing out where I might be wrong.

Thanks

By: Joshua C. Colp (jcolp) 2007-06-12 10:11:58

Quite... since this is now an architectural view this should go on the asterisk-dev mailing list so others can give their view and participate.