[asterisk-commits] lmadsen: branch 1.4 r250613 - /branches/1.4/doc/localchannel.txt
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Wed Mar 3 15:28:06 CST 2010
Author: lmadsen
Date: Wed Mar 3 15:28:02 2010
New Revision: 250613
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=250613
Log:
Update existing Local channel documentation.
A complete re-write of the Local channel documentation has been performed, with
the existing information from localchannel.txt and localchannel.tex merged in.
(issue #16637)
Reported by: kobaz
Patches:
localchannel.tex uploaded by lmadsen (license 10)
localchannel.txt uploaded by lmadsen (license 10)
Tested by: lmadsen, jsmith, mmichelson
Modified:
branches/1.4/doc/localchannel.txt
Modified: branches/1.4/doc/localchannel.txt
URL: http://svnview.digium.com/svn/asterisk/branches/1.4/doc/localchannel.txt?view=diff&rev=250613&r1=250612&r2=250613
==============================================================================
--- branches/1.4/doc/localchannel.txt (original)
+++ branches/1.4/doc/localchannel.txt Wed Mar 3 15:28:02 2010
@@ -1,51 +1,424 @@
-The Local channel
------------------
-
-chan_local is a pseudo-channel. Use of this channel simply loops calls back into the dialplan in a different context. Useful for recursive routing.
-
-* Syntax:
-
- Local/extension at context[/nm]
-
-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.
-
-Adding "/m" at the end will cause chan_local to forward music on hold start and stop requests. Normally chan_local acts on them and it is started or stopped on the Local channel itself.
-
-* Purpose:
-
-The Local channel construct can be used to establish dialing into any part of the dialplan.
-
-Imagine you have a TE410P in your box. You want to do something for which you must use a Dial statement (for instance when dropping files in /var/spool/outgoing) but you do want to be able to use your dialplans least-cost-routes or other intelligent stuff. What you could do before we had chan_local was create a cross-link between two ports of the TE410P and then Dial out one port and in the other. This way you could control where the call was going.
-
-Of course, this was a nasty hack, and to make it more sensible, chan_local was built.
-
-The "Local" channel driver allows you to convert an arbitrary extension into a channel. It is used in a variety of places, including agents, etc.
-
-This also allows us to hop to contexts like a GoSub routine; See examples below.
-
-Examples:
----------
-
-[inbound] ; here falls all incoming calls
-exten => s,1,Answer
-exten => s,2,Dial(local/200 at internal,30,r)
-exten => s,3,Playback(sorrynoanswer)
-exten => s,4,Hangup
-
-[internal] ; here where our phones falls for default
-exten => 200,1,Dial(sip/blah)
-exten => 200,102,VoiceMail(${EXTEN}@default)
-
-exten => 201,1,Dial(zap/1)
-exten => 201,102,VoiceMail(${EXTEN}@default)
-
-exten => _0.,1,Dial(Zap/g1/${EXTEN:1}) ; outgoing calls with 0+number
-
-
-Caveats:
-If you use chan_local from a call-file and you want to pass channel variables into your context, make sure you append the '/n', because otherwise chan_local will 'optimize' itself out of the call-path, and the variables will get lost. i.e.
-
- Local/00531234567 at pbx becomes Local/00531234567 at pbx/n
-
-----------
-2004-01-17
+==================
+| 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.
+
+
+Examples
+========
+
+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:
+
+[devices]
+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 at extensions)
+exten => 201,n,Hangup()
+
+[extensions]
+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 at 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()
+application.
+
+
+ -- Executing [201 at 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 at devices:3] Dial("SIP/my_desk_phone-00000014", "Local/201 at extensions") in new stack
+ -- Called 201 at 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 at extensions:1] Verbose("Local/201 at 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 at extensions-7cf4;2. The
+part '-7cf4;2' is just the unique identifier, and will be different for you.
+
+
+ -- Executing [201 at extensions:2] Verbose("Local/201 at extensions-7cf4;2", "2,Inside channel: Local/201 at extensions-7cf4;2") in new stack
+ == Inside channel: Local/201 at 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 at extensions:3] Dial("Local/201 at 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:
+
+[devices]
+exten => 201,1,Verbose(2,Call desk phone and cellphone but with delay)
+exten => 201,n,Dial(Local/deskphone-201 at extensions&Local/cellphone-201 at extensions,30)
+exten => 201,n,Voicemail(201 at default,${IF($[${DIALSTATUS} = BUSY]?b:u)})
+exten => 201,n,Hangup()
+
+[extensions]
+; 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 at extensions
+ * Local/cellphone-201 at 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
+destinations?
+
+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
+destinations.
+
+[devices]
+exten => 201,1,NoOp()
+exten => 201,n,Dial(Local/201 at internal&Local/201 at external,30)
+exten => 201,n,Voicemail(201 at default,${IF($[${DEVICE_STATE} = BUSY]?b:u)})
+exten => 201,n,Hangup()
+
+[internal]
+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)
+
+[external]
+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 at devices
+Application: Playback
+Data: silence/1&tt-weasels
+
+Add the callfile information to a file such as 'callfile.new' 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
+command:
+
+*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.
+
+[devices]
+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 callfile.new /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 at 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
+callfile.
+
+ -- Executing [201 at devices:1] NoOp("Local/201 at devices-ecf0;2", "") in new stack
+ -- Executing [201 at devices:2] Set("Local/201 at 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 at devices:3] GotoIf("Local/201 at 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 at devices:4] Dial("Local/201 at 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 at devices-ecf0;2
+
+We answer the call.
+
+ > Channel Local/201 at devices-ecf0;1 was answered.
+ > Launching Playback(silence/1&tt-weasels) on Local/201 at devices-ecf0;1
+
+We then start playing back the files.
+
+ -- <Local/201 at devices-ecf0;1> Playing 'silence/1.slin' (language 'en')
+ == Spawn extension (devices, 201, 4) exited non-zero on 'Local/201 at 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 at 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
+============================
+
+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
+channel.
+
+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.
+
+For example, if we were calling a Local channel from the Dial() application, we
+could change:
+
+Dial(Local/201 at devices)
+
+...into the following line:
+
+Dial(Local/201 at devices/n)
+
+By adding /n to the end, our Local channel will now stay in the call path and
+not go away.
+
+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 then performs another
+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.
+
+Here is an overview of our call flow, and 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
+
+3) Our dialplan calls Dial(Local/2 at services) <-- notice no /n
+
+4) The Local channel then executes dialplan at extension 2 within the services
+ context
+
+5) Extension 2 within [services] then performs another Dial() to a SIP channel
+ with the line: Dial(SIP/PHONE_B,,L(60000:450000:15000))
+
+6) The call is then placed to SIP/PHONE_B which then answers the call.
+
+7) The Local channel 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.
+
+8) SIP/PHONE_A and SIP/PHONE_B then continue talking indefinitely.
+
+Now, if we were to modify 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 Dial(Local/2 at 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 outside of the Local channel so that when it is
+ optimized out of the call path, the information required to make L() work is
+ associated with the outside channel. For example:
+
+ Dial(Local/2 at 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
+ channel.
+
+ 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.
More information about the asterisk-commits
mailing list