Hangup exits early when trying to use Wait()

Im trying to execute a long running code in the hangup handler, but it exits early.

Here is the code:

[sipbutton]
exten => _XX,1,Set(ORIEXT=$[h~~${EXTEN}])
exten => _XX,2,Hangup()
exten => h,1,GotoIf($[${LEN(${ORIEXT})} > 2]?sipbutton,h,2:sipbutton,h,3)
exten => h,2,Goto(sipbutton,${ORIEXT},1)
exten => h,3,NoOp(ORIEXT = ${ORIEXT})

exten => h04,1,GotoIf($[“${DEVICE_STATE(Custom:Service04)}”=“NOT_INUSE”]?sipbutton,h04,2:sipbutton,h,3)
exten => h04,2,Set(DEVICE_STATE(Custom:Service04)=RINGING)
exten => h04,3,Wait(7)
exten => h04,4,Set(DEVICE_STATE(Custom:Service04)=BUSY)
exten => h04,5,Wait(40)
exten => h04,6,Set(DEVICE_STATE(Custom:Service04)=NOT_INUSE)
exten => h04,7,Goto(sipbutton,h,3)
exten => blf04,hint,Custom:Service04

This is connected to a blf button on the phone, which will execute a action, that takes 7 seconds, and then takes 40 seconds to “reload”, or more rightly, fill a water tank that takes 40 seconds to fill (haven’t yet written code for it, but it will be a wget command just before device status is set to RINGING). Of course, I dont want the phone to be in a call during that time, so I want to execute it in the hangup handler.

Problem is that the handler exits, early, so how can I force it to run until its done?

(The if cause in h04,1 is to prevent the button from being pressed while its busy doing its thing or “reloading”)

It looks like this:

-- Executing [04@sipbutton:1] Set("SIP/sip05-00000001", "ORIEXT=h04") in new stack
-- Executing [04@sipbutton:2] Hangup("SIP/sip05-00000001", "") in new stack

== Spawn extension (sipbutton, 04, 2) exited non-zero on ‘SIP/sip05-00000001’
– Executing [h@sipbutton:1] GotoIf(“SIP/sip05-00000001”, “1?sipbutton,h,2:sipbutton,h,3”) in new stack
– Goto (sipbutton,h,2)
– Executing [h@sipbutton:2] Goto(“SIP/sip05-00000001”, “sipbutton,h04,1”) in new stack
– Goto (sipbutton,h04,1)
– Executing [h04@sipbutton:1] GotoIf(“SIP/sip05-00000001”, “1?sipbutton,h04,2:sipbutton,h,3”) in new stack
– Goto (sipbutton,h04,2)
– Executing [h04@sipbutton:2] Set(“SIP/sip05-00000001”, “DEVICE_STATE(Custom:Service04)=RINGING”) in new stack
– Executing [h04@sipbutton:3] Wait(“SIP/sip05-00000001”, “7”) in new stack
== Spawn extension (sipbutton, h04, 3) exited non-zero on ‘SIP/sip05-00000001’

It seems it terminates on the wait command. Any ideas?

Its a local SIP phone, and the call on the BLF button terminates into the asterisk, so it would work for me if I just could hang up the SIP client and then let the asterisk leg of the call be alive somehow.

This should help : Asterisk cmd Wait Command - VoIP-Info

“If Wait() is run on a channel which has been hung up (i.e. from the ‘h’ extension), the Wait() application returns 0 immediately and no further processing of the ‘h’ extension priorities takes place. You can get around this with ‘System(path/to/sleep Xs)’, where ‘X’ is the number of seconds to wait. Nasty, but it works.”

This gave a new weird behaviour:

The execution works nice now:
– Executing [blf04@outgoing:1] Answer(“SIP/sip05-00000000”, “”) in new stack
– Executing [blf04@outgoing:2] Goto(“SIP/sip05-00000000”, “sipbutton,04,1”) in new stack
– Goto (sipbutton,04,1)
– Executing [04@sipbutton:1] Set(“SIP/sip05-00000000”, “ORIEXT=h04”) in new stack
– Executing [04@sipbutton:2] Hangup(“SIP/sip05-00000000”, “”) in new stack
== Spawn extension (sipbutton, 04, 2) exited non-zero on ‘SIP/sip05-00000000’
– Executing [h@sipbutton:1] GotoIf(“SIP/sip05-00000000”, “1?sipbutton,h,2:sipbutton,h,3”) in new stack
– Goto (sipbutton,h,2)
– Executing [h@sipbutton:2] Goto(“SIP/sip05-00000000”, “sipbutton,h04,1”) in new stack
– Goto (sipbutton,h04,1)
– Executing [h04@sipbutton:1] GotoIf(“SIP/sip05-00000000”, “1?sipbutton,h04,2:sipbutton,h,3”) in new stack
– Goto (sipbutton,h04,2)
– Executing [h04@sipbutton:2] Set(“SIP/sip05-00000000”, “DEVICE_STATE(Custom:Service04)=RINGING”) in new stack
– Executing [h04@sipbutton:3] System(“SIP/sip05-00000000”, “/usr/bin/sleep 7s”) in new stack
– Executing [h04@sipbutton:4] Set(“SIP/sip05-00000000”, “DEVICE_STATE(Custom:Service04)=BUSY”) in new stack
– Executing [h04@sipbutton:5] System(“SIP/sip05-00000000”, “/usr/bin/sleep 40s”) in new stack
– Executing [h04@sipbutton:6] Set(“SIP/sip05-00000000”, “DEVICE_STATE(Custom:Service04)=NOT_INUSE”) in new stack
– Executing [h04@sipbutton:7] Goto(“SIP/sip05-00000000”, “sipbutton,h,3”) in new stack
– Goto (sipbutton,h,3)
– Executing [h@sipbutton:3] NoOp(“SIP/sip05-00000000”, “ORIEXT = h04”) in new stack

BUT.

The call in the phone is active the whole session, which makes the phone occupied.
Any ideas how to fix?
Tried to not answer the channel at all at start, but then I get a busy tone after 48 seconds.

I’m happy the code is working now, I’m not really sure what could be causing the phone session active now, I’ll let someone else give more insight; However, I see on your output the first line:

Executing [blf04@outgoing:1] Answer(“SIP/sip05-00000000”, “”) in new stack

I would try adding on your dial-plan something like:
exten => _X.,1,Set(ORICHAN=${CHANNEL})

Before you Answer the call, then before : Executing [04@sipbutton:2] Hangup(“SIP/sip05-00000000”, “”) in new stack

add something like
exten => _XX,n,ChannelRedirect(${ORICHAN},sipbutton,${EXTEN},2)

hope that fix your problem, good luck

nope didn’t work.

Here is how the output looks:

== Using SIP RTP CoS mark 5
> 0x7f61780250c0 – Strict RTP learning after remote address set to: 192.168.1.25:5272
– Executing [blf04@outgoing:1] Set(“SIP/sip05-00000000”, “ORICHAN=SIP/sip05-00000000”) in new stack
– Executing [blf04@outgoing:2] Answer(“SIP/sip05-00000000”, “”) in new stack
– Executing [blf04@outgoing:3] Goto(“SIP/sip05-00000000”, “sipbutton,04,1”) in new stack
– Goto (sipbutton,04,1)
– Executing [04@sipbutton:1] Set(“SIP/sip05-00000000”, “ORIEXT=h04”) in new stack
– Executing [04@sipbutton:2] ChannelRedirect(“SIP/sip05-00000000”, “SIP/sip05-00000000,sipbutton,04,3”) in new stack
– Executing [04@sipbutton:3] Hangup(“SIP/sip05-00000000”, “”) in new stack
== Spawn extension (sipbutton, 04, 3) exited non-zero on ‘SIP/sip05-00000000’
– Executing [h@sipbutton:1] GotoIf(“SIP/sip05-00000000”, “1?sipbutton,h,2:sipbutton,h,3”) in new stack
– Goto (sipbutton,h,2)
– Executing [h@sipbutton:2] Goto(“SIP/sip05-00000000”, “sipbutton,h04,1”) in new stack
– Goto (sipbutton,h04,1)
– Executing [h04@sipbutton:1] GotoIf(“SIP/sip05-00000000”, “1?sipbutton,h04,2:sipbutton,h,3”) in new stack
– Goto (sipbutton,h04,2)
– Executing [h04@sipbutton:2] Set(“SIP/sip05-00000000”, “DEVICE_STATE(Custom:Service04)=RINGING”) in new stack
– Executing [h04@sipbutton:3] System(“SIP/sip05-00000000”, “/usr/bin/sleep 7s”) in new stack
– Executing [h04@sipbutton:4] Set(“SIP/sip05-00000000”, “DEVICE_STATE(Custom:Service04)=BUSY”) in new stack
– Executing [h04@sipbutton:5] System(“SIP/sip05-00000000”, “/usr/bin/sleep 40s”) in new stack
– Executing [h04@sipbutton:6] Set(“SIP/sip05-00000000”, “DEVICE_STATE(Custom:Service04)=NOT_INUSE”) in new stack
– Executing [h04@sipbutton:7] Goto(“SIP/sip05-00000000”, “sipbutton,h,3”) in new stack
– Goto (sipbutton,h,3)
– Executing [h@sipbutton:3] NoOp(“SIP/sip05-00000000”, “ORIEXT = h04”) in new stack

I guess im right that I in ChannelRedirect should change to 3, as by inserting the ChannelRedirect in the flow, the Hangup is now on 3 instead of 2.

Here is how the whole code looks like now:

[outgoing]
exten => _-cisco-serviceuri-blfpickup-blfXX,1,Set(ORICHAN=${CHANNEL})
exten => _-cisco-serviceuri-blfpickup-blfXX,2,Answer()
exten => _-cisco-serviceuri-blfpickup-blfXX,3,goto(sipbutton,${EXTEN:32},1)
exten => _blfXX,1,Set(ORICHAN=${CHANNEL})
exten => _blfXX,2,Answer()
exten => _blfXX,3,goto(sipbutton,${EXTEN:3},1)

[sipbutton]
exten => _XX,1,Set(ORIEXT=$[h~~${EXTEN}])
exten => _XX,2,ChannelRedirect(${ORICHAN},sipbutton,${EXTEN},3)
exten => _XX,3,Hangup()
exten => h,1,GotoIf($[${LEN(${ORIEXT})} > 2]?sipbutton,h,2:sipbutton,h,3)
exten => h,2,Goto(sipbutton,${ORIEXT},1)
exten => h,3,NoOp(ORIEXT = ${ORIEXT})

exten => h04,1,GotoIf($[“${DEVICE_STATE(Custom:Service04)}”=“NOT_INUSE”]?sipbutton,h04,2:sipbutton,h,3)
exten => h04,2,Set(DEVICE_STATE(Custom:Service04)=RINGING)
exten => h04,3,System(/usr/bin/sleep 7s)
exten => h04,4,Set(DEVICE_STATE(Custom:Service04)=BUSY)
exten => h04,5,System(/usr/bin/sleep 40s)
exten => h04,6,Set(DEVICE_STATE(Custom:Service04)=NOT_INUSE)
exten => h04,7,Goto(sipbutton,h,3)
exten => blf04,hint,Custom:Service04

maybe you need to add a ‘h’ extension to hangup the call on your [outgoing] context like
[outgoing]


exten => h,1,Hangup

and change the ChannelRedirect(${ORICHAN},sipbutton,${EXTEN},3) to:
ChannelRedirect(${ORICHAN},outgoing,h,1)

you can also test manually by doing on the CLI: core show channels , then: channel request hangup ; you may even consider using the System() function to call asterisk -rx “channel request hangup ” if that works, beyond that I’m out of ideas, I’ll let someone else give their thoughts

tried your code, didn’t work, call is still active.

Tried channel request hangup on the channel, nothing happens.

== Using SIP RTP CoS mark 5
> 0x7fd2b8024890 – Strict RTP learning after remote address set to: 192.168.1.25:5086
– Executing [blf04@outgoing:1] Set(“SIP/sip05-00000002”, “ORIEXT=h04”) in new stack
– Executing [blf04@outgoing:2] Answer(“SIP/sip05-00000002”, “”) in new stack
> 0x7fd2b8024890 – Strict RTP switching to RTP target address 192.168.1.25:5086 as source
– Executing [blf04@outgoing:3] Hangup(“SIP/sip05-00000002”, “”) in new stack
== Spawn extension (outgoing, blf04, 3) exited non-zero on ‘SIP/sip05-00000002’
– Executing [h@outgoing:1] GotoIf(“SIP/sip05-00000002”, “1?sipbutton,h04,1:outgoing,h,2”) in new stack
– Goto (sipbutton,h04,1)
– Executing [h04@sipbutton:1] GotoIf(“SIP/sip05-00000002”, “1?sipbutton,h04,2:sipbutton,h,3”) in new stack
– Goto (sipbutton,h04,2)
– Executing [h04@sipbutton:2] Set(“SIP/sip05-00000002”, “DEVICE_STATE(Custom:Service04)=RINGING”) in new stack
– Executing [h04@sipbutton:3] System(“SIP/sip05-00000002”, “/usr/bin/sleep 7s”) in new stack

No such command ‘core show ch’ (type ‘core show help core show ch’ for other possible commands)
*CLI> channel request hangup – Executing [h04@sipbutton:4] Set(“SIP/sip05-00000002”, “DEVICE_STATE(Custom:Service04)=BUSY”) in new stack
– Executing [h04@sipbutton:5] System(“SIP/sip05-00000002”, “/usr/bin/sleep 40s”) in new stack
ore show c annels
Channel Location State Application(Data)
SIP/sip05-00000002 h04@sipbutton:5 Up System(/usr/bin/sleep 40s)
1 active channel
1 active call
3 calls processed
*CLI> channel request hangup SIP/sip05-00000002
Requested Hangup on channel ‘SIP/sip05-00000002’
*CLI> core show channels
Channel Location State Application(Data)
SIP/sip05-00000002 h04@sipbutton:5 Up System(/usr/bin/sleep 40s)
1 active channel
1 active call
3 calls processed
*CLI>

The phone is a Cisco CP-8961 if that matters, the phone in series Cisco CP-8961, CP-9951, CP-9971.
Also I use the usecallmanager patch.

The phone hangs up fine when the asterisk finishes executing the dialplan, so it seems the problem is on the asterisk side.

I’m confused as to what you are actually trying to do, and I’m pretty sure it is over-engineered, but I’d particularly note that h extensions are not supposed to be used for long running operations.

I suspect what you need to do is to originate to a local channel, and use group counts to prevent multiple concurrent executions.

How I do that? I don’t think I need to use group counts, as I could directly read the devicestate of “Custom:Service04” to know if the long-running process is in progress and thus prevent a concurrent execution.

What im doing, is to run actions (physical actions, it could be everything from unlocking a door, which takes just a second, to pumping water into a tank, which would take 40 seconds) from BLF buttons on the phone.

The BLF buttons then return status of the physical object in question, so you can at a glance see the status of the object, like extinguished = object is ready/off (NOT_INUSE), lit red = object is reloading/on (BUSY), or blinking orange = object is in a “working state”, in “auto mode”, or “alarm state”.(RINGING).

I have a sidecar with 36 positions, so it will be well suited to house many buttons to execute actions.

I do know that, the particular reason for it is because it will “use up a channel” on the system during the operation without actually be used. But for me its not a big concern.

I’m suggesting a rather more radical redesign, in which you don’t have custom device states and simply limit to one invocation of the extension, at a time.

You use the Originate application to create the local channel.

The custom device states is required to get the BLF buttons to light in the correct colors, so I could aswell reuse them to limit invocation.

Using group counts will avoid race conditions, although the result of a race may actually be harmless, in this case.

This worked extremely well. The code looks like this now, and it works perfectly:

[outgoing]
exten => _-cisco-serviceuri-blfpickup-blfXX,1,Set(ORIEXT=$[h~~${EXTEN:32}])
exten => _-cisco-serviceuri-blfpickup-blfXX,2,Answer()
exten => _-cisco-serviceuri-blfpickup-blfXX,3,Hangup()
exten => _blfXX,1,Set(ORIEXT=$[h~~${EXTEN:3}])
exten => _blfXX,2,Answer()
exten => _blfXX,3,Hangup()
include => noblf

exten => h,1,GotoIf($[${LEN(${ORIEXT})} > 2]?outgoing,h,2:outgoing,h,3)
exten => h,2,Originate(Local/s@hangupchan,exten,sipbutton,${ORIEXT},1,60,a)
exten => h,3,NoOp()

[hangupchan]
exten => s,1,Answer()
exten => s,2,Wait(60)
exten => s,3,Hangup()

[sipbutton]
exten => h01,1,GotoIf($[${STAT(e,/var/secure_files/duress.txt)} = 1]?sipbutton,h01,2:sipbutton,h01,5)
exten => h01,2,Set(DEVICE_STATE(Custom:Service01)=NOT_INUSE)
exten => h01,3,System(rm /var/secure_files/duress.txt)
exten => h01,4,Hangup()
exten => h01,5,Set(DEVICE_STATE(Custom:Service01)=BUSY)
exten => h01,6,Set(FILE(/var/secure_files/duress.txt)=X)
exten => h01,7,Hangup()
exten => blf01,hint,Custom:Service01

exten => h02,1,GotoIf($[${STAT(e,/var/secure_files/authall.txt)} = 1]?sipbutton,h02,2:sipbutton,h02,5)
exten => h02,2,Set(DEVICE_STATE(Custom:Service02)=NOT_INUSE)
exten => h02,3,System(rm /var/secure_files/authall.txt)
exten => h02,4,Hangup()
exten => h02,5,Set(DEVICE_STATE(Custom:Service02)=BUSY)
exten => h02,6,Set(FILE(/var/secure_files/authall.txt)=X)
exten => h02,7,Hangup()
exten => blf02,hint,Custom:Service02

exten => h03,1,GotoIf($[“${DEVICE_STATE(Custom:Service03)}”=“NOT_INUSE”]?sipbutton,h03,2:sipbutton,h03,4)
exten => h03,2,Set(DEVICE_STATE(Custom:Service03)=BUSY)
exten => h03,3,Hangup()
exten => h03,4,GotoIf($[“${DEVICE_STATE(Custom:Service03)}”=“BUSY”]?sipbutton,h03,5:sipbutton,h03,7)
exten => h03,5,Set(DEVICE_STATE(Custom:Service03)=RINGING)
exten => h03,6,Hangup()
exten => h03,7,Set(DEVICE_STATE(Custom:Service03)=NOT_INUSE)
exten => h03,8,Hangup()
exten => blf03,hint,Custom:Service03

exten => h04,1,GotoIf($[“${DEVICE_STATE(Custom:Service04)}”=“NOT_INUSE”]?sipbutton,h04,2:sipbutton,h04,8)
exten => h04,2,Set(DEVICE_STATE(Custom:Service04)=BUSY)
exten => h04,3,System(‘/usr/bin/wget -O/dev/null -q http://192.168.1.150/relay/0?turn=on’)
exten => h04,4,Wait(8)
exten => h04,5,Set(DEVICE_STATE(Custom:Service04)=RINGING)
exten => h04,6,Wait(40)
exten => h04,7,Set(DEVICE_STATE(Custom:Service04)=NOT_INUSE)
exten => h04,8,Hangup()
exten => blf04,hint,Custom:Service04

exten => h05,1,GotoIf($[${STAT(e,/var/secure_files/dooropen.txt)} = 1]?sipbutton,h05,2:sipbutton,h05,5)
exten => h05,2,Set(DEVICE_STATE(Custom:Service05)=NOT_INUSE)
exten => h05,3,System(rm /var/secure_files/dooropen.txt)
exten => h05,4,Hangup()
exten => h05,5,Set(DEVICE_STATE(Custom:Service05)=BUSY)
exten => h05,6,Set(FILE(/var/secure_files/dooropen.txt)=X)
exten => h05,7,Hangup()
exten => blf05,hint,Custom:Service05

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.