Search code examples
luaasteriskpbx

Asterisk PBX - Infinite Loop when user disconnects while using 'Read' application from LUA


I'm configuring interactive dial plans for asterisk at the moment and because I already know some LUA I thought it'd be easier to go that route.

I have a start extension like this:

["h"] = function(c,e)
    app.verbose("Hung Up")
  end;

["s"] = function(c, e)
    local d = 0
    while d == 0 do
      say:hello()
      app.read("read_result", nil, 1)

      d = channel["read_result"].value;

      if d == 1 then
        say:goodbye()
      elseif d == 2 then
        call:forward('front desk')
      end

      d = 0
    end

    say:goodbye()
end;

As you can see, I want to repeat the instructions say:hello() whenever the user gives an invalid answer. However, if the user hangs up while app.read waits for their answer, asterisk ends up in an infinite loop since d will always be nil.

I WOULD check for d==nil to detect disconnection, but nil also shows up when the user just presses the # pound sign during app.read.

So far I've taken to using for loops instead of while to limit the maximum iterations that way, but I'd rather find out how to detect a disconnected channel. I can't find any documentation on that though.

I also tried setting up a h extension, but the program won't go to it when the user hangs up.

Asterisk Verbose Output:

[...]
-- Executing [s@test-call:1] read("PJSIP/2300-00000004", "read_result,,1")                │        test.lua:3: in main chunk
-- Accepting a maximum of 1 digit.                                                       │        [C]: ?
-- User disconnected                                                                      │root@cirro asterisk lua test.lua
-- Executing [s@test-call:1] read("PJSIP/2300-00000004", "read_result,,1")                │Global B
-- Accepting a maximum of 1 digit.                                                       │LocalB-B->a
-- User disconnected                                                                      │LocalB-A
-- Executing [s@test-call:1] read("PJSIP/2300-00000004", "read_result,,1")                │LocalB-A
-- Accepting a maximum of 1 digit.                                                       │LocalB-A
-- User disconnected                                                                      │root@cirro asterisk cp ~/test.call /var/spool/asterisk/outgoing
-- Executing [s@test-call:1] read("PJSIP/2300-00000004", "read_result,,1")
[...]

Thanks for any help you might be able to offer.


Solution

  • First of all you can see in app_read docs(and any other doc), that it return different values for incorrect execution(when channel is down).

    Also this exact app offer simplified way of determine result:

    core show application Read
    
      -= Info about application 'Read' =- 
    
    [Synopsis]
    Read a variable. 
    
    [Description]
    Reads a #-terminated string of digits a certain number of times from the user
    in to the given <variable>.
    This application sets the following channel variable upon completion:
    ${READSTATUS}: This is the status of the read operation.
        OK
        ERROR
        HANGUP
        INTERRUPTED
        SKIPPED
        TIMEOUT
    

    If that still not suite you, you can direct ask asterisk about CHANNEL(state)

    PS You NEVER should write dialplan or any other program with infinite loop. Count your loops and exit at 10+. This will save ALOT of money for client.