Asterisk Documentation 1.4 localchannel.txt

-=NOTE: These pages are automatically updated once per
day from the Asterisk subversion repository when the repository changes revisions. Any
changes made to this page will be automatically overwritten with the
latest version from

| Local Channels |

In Asterisk, Local channels are a method used to treat an extension in the 
dialplan as if it were an external device. In essense, Asterisk will send the
call back into the dialplan as the destination of the call, versus sending the
call to a device.  

Two of the most common areas where Local channels are used include members 
configured for queues, and in use with callfiles. There are also other uses
where you want to ring two destinations, but with different information, such as
different callerID for each outgoing request.


Local channels are best demonstrated through the use of an example. Our first
example isn't terribly useful, but will demonstrate how Local channels can 
execute dialplan logic by dialing from the Dial() application.

Trivial Local channel example

In our dialplan (extensions.conf), we can Dial() another part of the dialplan
through the use Local channels. To do this, we can use the following dialplan:

exten => 201,1,Verbose(2,Dial another part of the dialplan via the Local chan)
exten => 201,n,Verbose(2,Outside channel:  ${CHANNEL})
exten => 201,n,Dial(Local/201@extensions)
exten => 201,n,Hangup()

exten => 201,1,Verbose(2,Made it to the Local channel)
exten => 201,n,Verbose(2,Inside channel:  ${CHANNEL})
exten => 201,n,Dial(SIP/some-named-extension,30)
exten => 201,n,Hangup()

The output of the dialplan would look something like the following. The output
has been broken up with some commentary to explain what we're looking at.

    -- Executing [201@devices:1] Verbose("SIP/my_desk_phone-00000014", "2,Dial another part of the dialplan via the Local chan") in new stack
  == Dial another part of the dialplan via the Local chan

We dial extension 201 from SIP/my_desk_phone which has entered the [devices]
context. The first line simply outputs some information via the Verbose()

    -- Executing [201@devices:2] Verbose("SIP/my_desk_phone-00000014", "2,Outside channel:  SIP/my_desk_phone-00000014") in new stack
  == Outside channel:  SIP/my_desk_phone-00000014

The next line is another Verbose() application statement that tells us our
current channel name. We can see that the channel executing the current dialplan
is a desk phone (aptly named 'my_desk_phone').

    -- Executing [201@devices:3] Dial("SIP/my_desk_phone-00000014", "Local/201@extensions") in new stack
    -- Called 201@extensions

Now the third step in our dialplan executes the Dial() application which calls
extension 201 in the [extensions] context of our dialplan. There is no
requirement that we use the same extension number -- we could have just as
easily used a named extension, or some other number. Remember that we're dialing
another channel, but instead of dialing a device, we're "dialing" another part
of the dialplan.

    -- Executing [201@extensions:1] Verbose("Local/201@extensions-7cf4;2", "2,Made it to the Local channel") in new stack
  == Made it to the Local channel

Now we've verified we've dialed another part of the dialplan. We can see the
channel executing the dialplan has changed to Local/201@extensions-7cf4;2. The
part '-7cf4;2' is just the unique identifier, and will be different for you.

    -- Executing [201@extensions:2] Verbose("Local/201@extensions-7cf4;2", "2,Inside channel:  Local/201@extensions-7cf4;2") in new stack
  == Inside channel:  Local/201@extensions-7cf4;2

Here we use the Verbose() application to see what our current channel name is.
As you can see the current channel is a Local channel which we created from our
SIP channel.

    -- Executing [201@extensions:3] Dial("Local/201@extensions-7cf4;2", "SIP/some-named-extension,30") in new stack

And from here, we're using another Dial() application to call a SIP device
configured in sip.conf as [some-named-extension].

Now that we understand a simple example of calling the Local channel, let's
expand upon this example by using Local channels to call two devices at the same
time, but delay calling one of the devices.

Delay dialing devices

Lets say when someone calls extension 201, we want to ring both the desk phone
and their cellphone at the same time, but we want to wait about 6 seconds to
start dialing the cellphone. This is useful in a situation when someone might be
sitting at their desk, but don't want both devices ringing at the same time, but
also doesn't want to wait for the full ring cycle to execute on their desk phone
before rolling over to their cellphone.

The dialplan for this would look something like the following:

exten => 201,1,Verbose(2,Call desk phone and cellphone but with delay)
exten => 201,n,Dial(Local/deskphone-201@extensions&Local/cellphone-201@extensions,30)
exten => 201,n,Voicemail(201@default,${IF($[${DIALSTATUS} = BUSY]?b:u)})
exten => 201,n,Hangup()

; Dial the desk phone
exten => deskphone-201,1,Verbose(2,Dialing desk phone of extension 201)
exten => deskphone-201,n,Dial(SIP/0004f2040001)  ; SIP device with MAC address
                                                 ; of 0004f2040001

; Dial the cellphone
exten => cellphone-201,1,Verbose(2,Dialing cellphone of extension 201)
exten => cellphone-201,n,Verbose(2,-- Waiting 6 seconds before dialing)
exten => cellphone-201,n,Wait(6)
exten => cellphone-201,n,Dial(DAHDI/g0/14165551212)

When someone dials extension 201 in the [devices] context, it will execute the
Dial() application, and call two Local channels at the same time:

 * Local/deskphone-201@extensions
 * Local/cellphone-201@extensions

It will then ring both of those extensions for 30 seconds before rolling over to
the Voicemail() application and playing the appropriate voicemail recording
depending on whether the ${DIALSTATUS} variable returned BUSY or not.

When reaching the deskphone-201 extension, we execute the Dial() application
which calls the SIP device configured as '0004f204001' (the MAC address of the
device). When reaching the cellphone-201 extension, we dial the cellphone via
the DAHDI channel using group zero (g0) and dialing phone number 1-416-555-1212.

Dialing destinations with different information

With Asterisk, we can place a call to multiple destinations by separating the
technology/destination pair with an ampersand (&). For example, the following
Dial() line would ring two separate destinations for 30 seconds:

exten => 201,1,Dial(SIP/0004f2040001&DAHDI/g0/14165551212,30)

That line would dial both the SIP/0004f2040001 device (likely a SIP device on
the network) and dial the phone number 1-416-555-1212 via a DAHDI interface. In
our example though, we would be sending the same callerID information to both
end points, but perhaps we want to send a different callerID to one of the

We can send different callerIDs to each of the destinations if we want by using
the Local channel. The following example shows how this is possible because we
would Dial() two different Local channels from our top level Dial(), and that
would then execute some dialplan before sending the call off to the final

exten => 201,1,NoOp()
exten => 201,n,Dial(Local/201@internal&Local/201@external,30)
exten => 201,n,Voicemail(201@default,${IF($[${DEVICE_STATE} = BUSY]?b:u)})
exten => 201,n,Hangup()

exten => 201,1,Verbose(2,Placing internal call for extension 201)
exten => 201,n,Set(CALLERID(name)=From Sales)
exten => 201,n,Dial(SIP/0004f2040001,30)

exten => 201,1,Verbose(2,Placing external call for extension 201)
exten => 201,n,Set(CALLERID(name)=Acme Cleaning)
exten => 201,n,Dial(DAHDI/g0/14165551212)

With the dialplan above, we've sent two different callerIDs to the destinations:

 * "From Sales" was sent to the local device SIP/0004f2040001
 * "Acme Cleaning" was sent to the remote number 1-416-555-1212 via DAHDI

Because each of the channels is independent from the other, you could perform
any other call manipulation you need. Perhaps the 1-416-555-1212 number is a
cell phone and you know you can only ring that device for 18 seconds before the
voicemail would pick up. You could then limit the length of time the external
number is dialed, but still allow the internal device to be dialed for a longer
period of time.

Using callfiles and Local channels

Another example is to use callfiles and Local channels so that you can execute
some dialplan prior to performing a Dial(). We'll construct a callfile which 
will then utilize a Local channel to lookup a bit of information in the AstDB 
and then place a call via the channel configured in the AstDB.

First, lets construct our callfile that will use the Local channel to do some
lookups prior to placing our call. More information on constructing callfiles is
located in the doc/callfiles.txt file of your Asterisk source.

Our callfile will simply look like the following:

Channel: Local/201@devices
Application: Playback
Data: silence/1&tt-weasels

Add the callfile information to a file such as '' or some other
appropriately named file.

Our dialplan will perform a lookup in the AstDB to determine which device to
call, and will then call the device, and upon answer, Playback() the silence/1
(1 second of silence) and the tt-weasels sound files.

Before looking at our dialplan, lets put some data into AstDB that we can then
lookup from the dialplan. From the Asterisk CLI, run the following command:

*CLI> database put phones 201/device SIP/0004f2040001

We've now put the device destination (SIP/0004f2040001) into the 201/device key
within the phones family. This will allow us to lookup the device location for
extension 201 from the database.

We can then verify our entry in the database using the 'database show' CLI

*CLI> database show
/phones/201/device                               : SIP/0004f2040001

Now lets create the dialplan that will allow us to call SIP/0004f2040001 when we
request extension 201 from the [extensions] context via our Local channel.

exten => 201,1,NoOp()
exten => 201,n,Set(DEVICE=${DB(phones/${EXTEN}/device)})
exten => 201,n,GotoIf($[${ISNULL(${DEVICE})}]?hangup) ; if nothing returned,
                                                      ; then hangup
exten => 201,n,Dial(${DEVICE},30)
exten => 201,n(hangup(),Hangup()

Then, we can perform a call to our device using the callfile by moving it into
the /var/spool/asterisk/outgoing/ directory.

# mv /var/spool/asterisks/outgoing

Then after a moment, you should see output on your console similar to the
following, and your device ringing. Information about what is going on during
the output has also been added throughout.

    -- Attempting call on Local/201@devices for application Playback(silence/1&tt-weasels) (Retry 1)

You'll see the line above as soon as Asterisk gets the request from the 

    -- Executing [201@devices:1] NoOp("Local/201@devices-ecf0;2", "") in new stack
    -- Executing [201@devices:2] Set("Local/201@devices-ecf0;2", "DEVICE=SIP/0004f2040001") in new stack

This is where we performed our lookup in the AstDB. The value of 
SIP/0004f2040001 was then returned and saved to the DEVICE channel variable.

    -- Executing [201@devices:3] GotoIf("Local/201@devices-ecf0;2", "0?hangup") in new stack

We perform a check to make sure ${DEVICE} isn't NULL. If it is, we'll just
hangup here.

    -- Executing [201@devices:4] Dial("Local/201@devices-ecf0;2", "SIP/0004f2040001,30") in new stack
    -- Called 000f2040001
    -- SIP/0004f2040001-00000022 is ringing

Now we call our device SIP/0004f2040001 from the Local channel.

    -- SIP/0004f2040001-00000022 answered Local/201@devices-ecf0;2

We answer the call.

       > Channel Local/201@devices-ecf0;1 was answered.
       > Launching Playback(silence/1&tt-weasels) on Local/201@devices-ecf0;1

We then start playing back the files.

    -- <Local/201@devices-ecf0;1> Playing 'silence/1.slin' (language 'en')
  == Spawn extension (devices, 201, 4) exited non-zero on 'Local/201@devices-ecf0;2'

At this point we now see the Local channel has been optimized out of the call
path. This is important as we'll see in examples later. By default, the Local
channel will try to optimize itself out of the call path as soon as it can. Now
that the call has been established and audio is flowing, it gets out of the way.

    -- <SIP/0004f2040001-00000022> Playing 'tt-weasels.ulaw' (language 'en')
[Mar  1 13:35:23] NOTICE[16814]: pbx_spool.c:349 attempt_thread: Call completed to Local/201@devices

We can now see the tt-weasels file is played directly to the destination
(instead of through the Local channel which was optimized out of the call path)
and then a NOTICE stating the call was completed.

Understanding When To Use /n

Lets take a look at an example that demonstrates when the use of the /n 
directive is necessary. If we spawn a Local channel which does a Dial()
to a SIP channel, but we use the L() option (which is used to limit the
amount of time a call can be active, along with warning tones when the
time is nearly up), it will be associated with the Local channel,
which is then optimized out of the call path, and thus won't perform
as expected.

This following dialplan will not perform as expected.

exten => 2,1,Dial(SIP/PHONE_B,,L(60000:45000:15000))

exten => 4,1,Dial(Local/2@services)

By default, the Local channel will try to optimize itself out of the call path.
This means that once the Local channel has established the call between the
destination and Asterisk, the Local channel will get out of the way and let
Asterisk and the end point talk directly, instead of flowing through the Local

This can have some adverse effects when you're expecting information to be
available during the call that gets associated with the Local channel. When the
Local channel is optimized out of the call path, any Dial() flags, or channel
variables associated with the Local channel are also destroyed and are no longer
available to Asterisk.

We can force the Local channel to remain in the call path by utilizing the /n
directive. By adding /n to the end of the channel definition, we can keep the
Local channel in the call path, along with any channel variables, or other
channel specific information.

In order to make this behave as we expect (limiting the call), we would change:

exten => 4,1,Dial(Local/2@services)

...into the following:

exten => 4,1,Dial(Local/2@services/n)

By adding /n to the end, our Local channel will now stay in the call path and
not go away.

Why does adding the /n option all of a suddon make the 'L' option work? First
we need to show an overview of the call flow that doesn't work properly, and
discuss the information associated with the channels:

1) SIP device PHONE_A calls Asterisk via a SIP INVITE

2) Asterisk accepts the INVITE and then starts processing dialplan logic in
   the [internal] context.

3) Our dialplan calls Dial(Local/2@services)  <-- notice no /n

4) The Local channel then executes dialplan at extension 2 within the [services]

5) Extension 2 within [services] then performs Dial() to PHONE_B
   with the line:  Dial(SIP/PHONE_B,,L(60000:45000:15000))

6) SIP/PHONE_B then answers the call.

7) Even though the L option was given when dialing the SIP device, the L
   information is stored in the channel that is doing the Dial() which is the Local
   channel, and not the endpoint SIP channel.

8) The Local channel in the middle, containing the information for tracking the
   time allowance of the call, is then optimized out of the call path, losing all
   information about when to terminate the call.

9) SIP/PHONE_A and SIP/PHONE_B then continue talking indefinitely.

Now, if we were to add /n to our dialplan at step three (3) then we would force the
Local channel to stay in the call path, and the L() option associated with the
Dial() from the Local channel would remain, and our warning sounds and timing
would work as expected.

There are two workarounds for the above described scenario:

1) Use what we just described, Dial(Local/2@services/n) to cause the Local
   channel to remain in the call path so that the L() option used inside the
   Local channel is not discarded when optimization is performed.

2) Place the L() option at the outermost part of the path so that when the middle
   is optimized out of the call path, the information required to make L() work
   is associated with the outside channel. The L information will then be stored
   on the calling channel, which is PHONE_A. For example: 

   exten => 2,1,Dial(SIP/PHONE_B)
   exten => 4,1,Dial(Local/2@services,,L(60000:45000:15000))

Local channel modifiers

There are additional modifiers for the Local channel as well. They include:

 * 'n' -- Adding "/n" at the end of the string will make the Local channel not 
          do a native transfer (the "n" stands for "n"o release) upon the remote
          end answering the line. This is an esoteric, but important feature if
          you expect the Local channel to handle calls exactly like a normal
          channel. If you do not have the "no release" feature set, then as soon
          as the destination (inside of the Local channel) answers the line and
          one audio frame passes, the variables and dial plan will revert back
          to that of the original call, and the Local channel will become a
          zombie and be removed from the active channels list. This is desirable
          in some circumstances, but can result in unexpected dialplan behavior
          if you are doing fancy things with variables in your call handling.

 * 'j' -- Adding "/j" at the end of the string allows you to use the generic
          jitterbuffer on incoming calls going to Asterisk applications. For 
          example, this would allow you to use a jitterbuffer for an incoming
          SIP call to Voicemail by putting a Local channel in the middle. The 
          'j' option must be used in conjunction with the 'n' option to make
          sure that the Local channel does not get optimized out of the call.

          This option is available starting in the Asterisk 1.6.0 branch.

 * 'm' -- Using the "/m" option will cause the Local channel to forward music on
          hold (MoH) start and stop requests. Normally the Local channel acts on
          them and it is started or stopped on the Local channel itself. This
          options allows those requests to be forwarded through the Local

          This option is available starting in the Asterisk 1.4 branch.

 * 'b' -- The "/b" option causes the Local channel to return the actual channel
          that is behind it when queried. This is useful for transfer scenarios
          as the actual channel will be transferred, not the Local channel.

          This option is available starting in the Asterisk 1.6.0 branch.

Created by: josiahbryan, Last modification: Sun 25 of Jul, 2010 (08:41 UTC)
Please update this page with new information, just login and click on the "Edit" or "Discussion" tab. Get a free login here: Register Thanks! - Find us on Google+