Internal calls between different contexts

Hello,

I’m new to Asterisk so apologies of I am asking a basic question. I am trying to work out how to make internal calls between two different contexts.

The following allows a call from 8001 to 6001, but not the other way around:

[one-phones]
include => one-outbound
include => stdexten
include => two-phones

exten => 6001,1,Gosub(6001,stdexten(PJSIP/6001))
       same => n,Goto(s,end)

[two-phones]
;include => two-outbound
include => stdexten
include => one-phones

exten => 8001,1,Gosub(8001,stdexten(PJSIP/8001))
       same => n,Goto(s,end)

exten => *8001,1,VoiceMailMain(8001@vm)
       same => n,Hangup

I am not even sure if I am approaching things correctly. My aim is to have extension 6001 receiving and making outbound calls on one sip trunk with extension 8001 making and receiving calls on a second separate sip trunk. However, I would like each extension to still be able to make internals call to each other.

Any advice on the correct way to tackle this would be appreciated.

You haven’t provided the definition of the label stdexten! I suspect it is worse than this, but without the full dialplan, I can’t be sure.

The normal solution is to have an internal context, which includes all the internal extensions, and include that in individual contexts, which handle outbound calls.

Thanks for the response David.

The [stdext] section is as follows:

[stdexten]
exten => _X.,50000(stdexten),NoOp(Start stdexten)
        same => n,Set(LOCAL(ext)=${EXTEN})
        same => n,Set(LOCAL(dev)=${ARG1})
        same => n,Set(LOCAL(cntx)=${ARG2})
        same => n,Set(LOCAL(mbx)=${ext}${IF($[!${ISNULL(${cntx})}]?@${cntx})})
        same => n,Dial(${dev},20)                               ; Ring the interface, 20 seconds maximum
        same => n,Goto(stdexten-${DIALSTATUS},1)                ; Jump based on status (NOANSWER,BUSY,CHANUNAVAIL,CONGESTION,ANSWER)

exten => stdexten-NOANSWER,1,VoiceMail(${mbx}@vm,u)        ; If unavailable, send to voicemail w/ unavail announce
        same => n,Return()                      ; If they press #, return to start

exten => stdexten-BUSY,1,VoiceMail(${mbx}@vm,b)            ; If busy, send to voicemail w/ busy announce
        same => n,Return()                      ; If they press #, return to start

exten => _stde[x]te[n]-.,1,Goto(stdexten-NOANSWER,1)    ; Treat anything else as no answer

exten => a,1,VoiceMailMain(${mbx}@vm)                      ; If they press *, send the user into VoicemailMain
exten => a,n,Return()

I’ve been playing with this one and off for a few months, but I believe I have only adjust the voice mail section of [stdexten]. It was in the default extensions file that installed from the ubuntu 24.04 asterisk install.

As suggest, I will group all extensions in the same context and look into getting each extension to use a specific sip trunk.

You don’t have a priority called stdexten in any of your extensions.

I haven’t put much time into getting my head around the extensions config yet so I am sure it will be incorrect.

The config I used for the extensions also came from the default extensions.conf file that ubuntu installed. I used this section and adjusted it:

;exten => 112,1,Gosub(112,stdexten(SIP/nancy_1,acme))
;       same => n,Goto(s,end)
;
; end of acme example

Copying these sections of the default file seemed the get asterisk working on my LAN. I can call extensions and make and received external calls.

I initial got asterisk seeming working fairly quickly. Since then I been spending most my time failing to get a softphone to work over a VPN.

If you have any corrections to suggest I would welcome them? Or, if anyone could point me in the direction of a simple extension.conf file that I could use to learn and test with I would also welcome that.

I see the label now.

end isn’t defined.

I decided to have another look at the dialplan using the file in the following link:

https://github.com/asterisk/asterisk/blob/master/configs/basic-pbx/extensions.conf

I have most it it working except the External-Features. I can’t dial an extension direct by adding the extension number to the end of the DID.

My adjusted extensions file is as follows:

[globals]
; General internal dialing options used in context Dial-Users.
; Only the timeout is defined here. See the Dial app documentation for
; additional options.
INTERNAL_DIAL_OPT=,30

[Hints]
; Allow dynamic hint creation for every extension.
exten = _11XX,hint,PJSIP/${EXTEN}

[Features]
; Extension to check user voicemail. We don't require the user to enter
; their pincode.
exten = 8000,1,Verbose(1, "User ${CALLERID(num)} dialed the voicemail feature.")
 same = n,VoiceMailMain(${CALLERID(num)}@vm,s)
 same = n,Hangup()

; Exten to dial the main IVR internally.
exten = 1100,1,Verbose(1, "User ${CALLERID(num)} dialed the IVR.")
 same = n,Goto(Main-IVR,441234123456,1)

;Extension to enter a conference intended only for employees
exten = 6000,1,Verbose(1, "User ${CALLERID(num)} dialed the employee conference.")
 same = n,Confbridge(employees)
 same = n,Hangup()

;Extension to enter a conference intended for employees and customers
exten = 6500,1,Verbose(1, "User ${CALLERID(num)} dialed the employee/customer mixed conference.")
 same = n,Confbridge(mixed)
 same = n,Hangup()

[External-Features]
; Extension for users to remotely check voicemail. Here we require the caller to
; enter their mailbox and pincode.
exten = 4412341234561234,1,Verbose(1, "User ${CALLERID(num)} dialed into remote voicemail.")
 same = n,VoiceMailMain(example)
 same = n,Hangup()

; Extension to queue for sales.
; The queue has a 300 second timeout.
exten = 4412341234561200,1,Verbose(1, "User ${CALLERID(num)} dialed the sales queue.")
 same = n,Answer()
 same = n,Queue(sales,,,,300)
 same = n,Goto(operator,1)

; Extension to queue for a customer advocate.
; The queue has a 1200 second timeout.
exten = 4412341234561250,1,Verbose(1, "User ${CALLERID(num)} dialed the customer advocate queue.")
 same = n,Answer()
 same = n,Queue(customer_advocate,,,,1200)
 same = n,Goto(operator,1)

[Dialing-Errors]
; Handle any extensions dialed internally that don't otherwise exist.
; Comment out or remove this extension if you would rather have the calls
; ignored.
exten = _X.,1,Verbose(1, "User ${CALLERID(num)} dialed an invalid number.")
 same = n,Playback(pbx-invalid)
 same = n,Hangup()

[Internal-Setup]
; Here we capture internal calls to do anything we need to do before sending
; them onto all the possible internal locations. Such as disabling CDR on
; internal to internal calls.
exten = _X.,1,NoOp()
 same = n,Set(CDR_PROP(disable)=1)
 same = n,Goto(Internal-Main,${EXTEN},1)

; The Internal-Main context provides a way for internal callers to get access to most
; features and functions configured for them. External callers may be sent
; directly to some of the contexts you see included here, so the included
; contexts are not necessarily internal only.
[Internal-Main]
; The order of includes here is important for matching the right extensions.
include = Hints
include = Features
include = Dial-Users
include = Dialing-Errors

; Dial-Users handles calls to internal extensions.
; Calls coming into this context may be *external* or *internal* in origin.
[Dial-Users]
exten = _11XX,1,Verbose(1, "User ${CALLERID(num)} dialed ${EXTEN}.")
 same = n,Set(SAC_DIALED_EXTEN=${EXTEN})
 same = n,Gotoif($[${DEVICE_STATE(PJSIP/${EXTEN})} = BUSY]?dialed-BUSY,1:)
 same = n,Dial(PJSIP/${EXTEN}${INTERNAL_DIAL_OPT})
 same = n,Goto(dialed-${DIALSTATUS},1)

exten = dialed-NOANSWER,1,NoOp()
 same = n,Voicemail(${SAC_DIALED_EXTEN}@vm,u)
 same = n,Hangup()

exten = dialed-BUSY,1,NoOp()
 same = n,Voicemail(${SAC_DIALED_EXTEN}@vm,b)
 same = n,Hangup()

exten = dialed-CHANUNAVAIL,1,NoOp()
 same = n,Playback(pbx-invalid)
 same = n,Hangup()

exten = _dialed-.,1,Goto(dialed-NOANSWER,1)

exten = h,1,Hangup()

; Callers in the directory may dial 0 which will jump to the
; 'o' extension.
exten = o,1,Goto(1111)

; Outbound-Dial
;
; Before we dial, see if the extension matches our restricted number patterns.
; Note that this is a basic set of numbers which could incur a fee if dialed.
; The NANP includes many other numbers that you may want to block. If you feel
; it is necessary to block further number patterns you'll have to add them below
; or you may consider implementing a blacklist via methods beyond the scope of
; this example.
[Outbound-Dial]
exten = _00.,1,Hangup()
;exten = _900NXXXXXX,1,Hangup()
;exten = _1900NXXXXXX,1,Hangup()
;exten = _976XXXX,1,Hangup()
;exten = _NXX976XXXX,1,Hangup()
;exten = _1NXX976XXXX,1,Hangup()
; Dial outbound through our SIP ITSP.
exten = _X.,1,Verbose(1, "Didn't match any restricted numbers, proceeding with outbound dial.")
 same = n,Set(CALLERID(num)=01234123456${CALLERID(num)})
 same = n,Dial(PJSIP/${EXTEN}@aaisptrunk)
 same = n,Hangup()

; Calls from internal endpoints will enter into one of the two following
; contexts based on their dialing privilege.
[Local]
include = Internal-Setup

exten = _XXXXXX,1,Goto(Outbound-Dial,01234${EXTEN},1)

[Long-Distance]
include = Local

exten = _0X.,1,Goto(Outbound-Dial,${EXTEN},1)

; The DID-Extensions context captures inbound calls from our ITSP that have a
; DID number where the last four digits matches an internal extension.
[DID-Extensions]
exten = _44123412345611XX,1,Verbose(1, "External caller dialed inbound to DID ${EXTEN})")
 same = n,Goto(Dial-Users,${EXTEN:-4:4},1)

; Our main IVR program for receiving inbound callers.
; The IVR script reads “Thank you for calling Super Awesome Company, Waldo’s
; premier provider of perfect products. If you know your party’s extension,
; you may dial it at any time. To establish a sales partnership, press one. To
; speak with a customer advocate, press two. For accounting and other
; receivables, press three. For a company directory, press four. For an
; operator, press zero.”
; demo-congrats is currently used as a placeholder.
[Main-IVR]
exten = 441234123456,1,Verbose(1, "New caller, ${CALLERID(num)} dialed into the IVR.")
 same = n,Answer()
 same = n(start),Background(basic-pbx-ivr-main)
 same = n,WaitExten(10)
 same = n,Background(basic-pbx-ivr-main)
 same = n,Hangup()

exten = 0,1,Verbose(1, "Caller ${CALLERID(num)} dialed the operator.")
 same = n,Goto(Dial-Users,1111,1)
exten = 1,1,Verbose(1, "Caller ${CALLERID(num)} dialed the Sales queue.")
 same = n,Goto(External-Features,4412341234561200,1)
exten = 2,1,Verbose(1, "Caller ${CALLERID(num)} dialed the Customer Experience queue.")
 same = n,Goto(External-Features,4412341234561250,1)
exten = 3,1,Verbose(1, "Caller ${CALLERID(num)} dialed Accounting and Receivables.")
 same = n,Goto(Dial-Users,1101,1)
exten = 4,1,Verbose(1, "Caller ${CALLERID(num)} dialed the directory.")
 same = n,Directory(example,Dial-Users)

exten = i,1,Playback(option-is-invalid)
 same = n,Goto(441234123456,start)

exten = t,1,Playback(are-you-still-there)
 same = n,Goto(441234123456,start)

; Calls from our ITSP SIP account arrive in AA-Incoming. We should be careful
; to route calls very explicitly so as to avoid any security issues, such as
; accidentally giving outbound dial access to inbound callers.
;
; Each context includes extension pattern matching to match the inbound DID
; dialed appropriately.
[AA-Incoming]
include = Main-IVR
include = DID-Extensions
include = External-Features

I think I can work out how to direct an incoming trunk to a specific extension or IVR, but I am still not sure how to get a specific extension to use a separate sip trunk.

My suspicion is I have messed up the UK DID numbers I have added to the file. Any advice would be appreciated.

I think you mean an endpoint, not an extension.

You give the endpoint its own context, and that either directly contains the extension that dials the trunk, or sets a variable, containing the trunk endpoint name, before going to to generic code, that does the Dial call.

Thanks David, I have been am using the term extensions to help me to get my head around things, as I have noticed the the sip trunk is also referred to as an endpoint.

The separate context is slightly confusing as I was thinking about that route initially, but I wanted make sure that each extension endpoint can still contact each other. Do you know if there are the an example config anywhere with something similar that I could be pointed too, as this would help me understand how to do this?

Also, do you have any pointers on what is preventing the direct dial of extension endpoints from the siptrunk? If I wait for the IVR then dial the extension endpoint it works! I think my number stripping may be wrong in the [DID-Extensions] section, and/or I have messed up the the DID numbers when I changed the example extensions.conf file.

I think this only works in Germany, and even then you probably have to have a formal direct in dialling service. UK direct in dialling is done within the standard number length. Typically you allocate 00 as the final digits that you publish for unfamiliar callers.

I think I have now solved the original query, but I have given myself another problem that cannot get the [External-Features] to work. And now I know these feature exists I have to try and get them to work!

What is the etiquette on this forum? Should I start another thread for this issue?

I’d say it is a judgement as to whether or not information in this thread is relevant.

I will make another post here then as most of the above extensions config will be relevant.

The contents of the pjsip.conf for the trunk registration are what I suspect may have something to do with problem so I will post the trunk config to see if anything obvious is apparent:

; Registration for AAISP Account

[reg_441234123456]
type = registration
retry_interval = 20
fatal_retry_interval = 20
forbidden_retry_interval = 20
max_retries = 9999
auth_rejection_permanent = no
contact_user = 441234123456
expiration = 120
outbound_auth = auth_reg_441234123456
client_uri = sip:+441234123456@voiceless.aa.net.uk
server_uri = sip:voiceless.aa.net.uk

[auth_reg_441234123456]
type = auth
password = Strong1InitBruv! <-- no it isn't 
username = +441234123456

; Endpoint for AAISP account

[aaisptrunk]
type = endpoint
context = AA-Incoming
dtmf_mode = rfc4733
disallow = all
allow = alaw
allow = ulaw
direct_media = no
rtp_symmetric = yes
aors = aaisptrunk
outbound_auth = auth_reg_441234123456

[aaisptrunk]
type = aor
contact = sip:+441234123456@voiceless.aa.net.uk
qualify_frequency = 20

[aaisptrunk]
type = identify
endpoint = aaisptrunk
match = voiceless.aa.net.uk

I’ve tried a few different options for the contact_user setting but nothing has worked so far.

Does anything in the trunk settings standout and as being the likely cause of the [External-Features] problem?

Again you are not in Germany. Maybe A&A does something special here, in which case you need to ask them, but, as far as I know it is still the case that UK PSTN originating exchanges know the maximum length for a given area code (often the only length) and stop accepting digits once that it reached, and immediately send the number forward.

If you want to do true DID, you need to rent a block of numbers, such that the number length is the normal length for the area code, even when some digits are only used by your system.

A&A do offer blocks of up to 100 numbers, but I assume a 100 number block will cost you, at least, £120 a month (more if there are desirable numbers in the range).

The 44 was replaced in all files with a 0. I left it in the post above to align with the earlier posted extensions config. I’ve tried different options in both the pjsip.conf and extensions.cong files and I wasn’t able to resolve the problem.

The second trunk I have is with sipgate and I think they may need to have the 44. I trying to get t the AA trunk working properly before I start look at sipgate.

I only need two numbers and I don’t believe I require true DID. If I can get this to work I will probably try setting everything up on a Pi4 to save power.

Please consider this thread solved. My config errors are obvious to me now!