aboutsummaryrefslogtreecommitdiffstats
path: root/doc/localchannel.txt
blob: be6017c2372d8cdf877e17816e77b7ca46e794ad (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
==================
| 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@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@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@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:

[devices]
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()

[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@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
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@internal&Local/201@external,30)
exten => 201,n,Voicemail(201@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@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@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@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.

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

[internal]
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
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.

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

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

...into the following:

[internal]
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]
   context.

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: 

   [services]
   exten => 2,1,Dial(SIP/PHONE_B)
   
   [internal]
   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
          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.