What is call parking?
Call parking is a means of placing a call on hold so anyone can retrieve the call if they know where the call is parked. The natural metaphor to describe how the feature operates is a car parking lot. In fact many of the call parking options use car parking terminology such as parking lots and parking spaces to describe what the options do.
Parking has had a few incarnations to add features throughout its history in Asterisk. In Asterisk 12 it got another overhaul because of the major architectural changes in Asterisk. The parking functionality was extracted from the Asterisk core to the res_parking.so loadable module. The cited references are for Asterisk 13 but most of the information will apply to Asterisk 11 with some alterations.
Looking at the pieces
Defining a parking lot can be done either statically in the res_parking.conf configuration file or dynamically using an existing parking lot as a template to create a new lot. I’ll describe creating dynamic parking lots after describing static parking lots. A parking lot basically needs a name, a range of parking spaces, and what to do with any calls that have been in the parking lot too long.
If you want Asterisk to manage the dialplan extensions associated with the parking lot you need to consider these additional options: context , parkext , parkext_exclusive , and parkinghints . For single entity parking setups, you should include the generated parking lot context into your dialplan context so you can park and retrieve calls using the managed extensions.
There are three applications that work to implement call parking. Two applications put channels into parking lots and one retrieves them. The Park application puts the channel executing the application into the parking lot. Like the Park application, the ParkAndAnnounce application also puts the channel executing the application into the parking lot. The ParkedCall application retrieves a parked channel at the requested parking lot and space.
There are two main differences between Park and ParkAndAnnounce. The first is where the audio announcement of where the channel is parked gets sent. Park will announce to the channel parking the call. ParkAndAnnounce will dial an announcing channel. When the announcing channel answers ParkAndAnnounce plays the audio announcement and hangs up. The second is that Park has special support to deal with the limitations of blind transfers that can also affect which parking lot is used.
The parking lot name used to park or retrieve a channel is searched for in the following order: 1) the application parking lot parameter value, 2) the PARKINGLOT channel variable value, 3) the function CHANNEL(parkinglot) value, and finally 4) the default parking lot. How you set the PARKINGLOT channel variable or function CHANNEL(parkinglot) value is up to you and your dialplan. The easiest way is to have the channel driver set a default value when the channel is created by using a varset or parkinglot option specific to the channel driver configuration.
You might be wondering why the Park and ParkAndAnnounce applications park the channel executing the application when you typically want to park the person you are talking with. To park the person you are talking with you have to transfer the person to the parking lot. For an attended transfer you actually park yourself and then transfer the other party into the parking lot to take your place. For a blind transfer you cause the other party to park himself.
An attended transfer has natural advantages over a blind transfer for call parking. Park can simply tell you where the call is parked before you complete the transfer. The parker has complete control into which parking lot the call is parked.
Blind transfers have limitations when it comes to parking. You normally cannot get an audio announcement from Park for where in the parking lot the call is parked. The parker channel is no longer available to hear the announcement. Even worse, the party being parked has some control into which parking lot they park themselves.
The Park application attempts to work around the blind transfer limitations by trying to detect if you are blind transferring to a parking extension. A parking extension is detected if the first dialplan extension priority is the Park application. A detected parking extension converts the blind transfer into a pseudo attended transfer that completes the transfer after the announcement. The Park application normally doesn’t actually get executed in the pseudo attended transfer work around. If the parking extension is not detected then you have no chance to hear where the call is parked and the call could get parked in an unexpected parking lot. The DTMF blind transfer feature can always successfully use the work around. The channel technology blind transfer method also uses the work around. However, the channel technology may not let you hear the location announcement. For example, the SIP protocol blind transfer method may not allow you to hear the location announcement as SIP phones may have already disconnected their audio path.
Note: The DTMF one-touch parking feature is a special case blind transfer and currently will not do anything if you don’t have Asterisk managing dialplan extensions for the parking lot.
Dynamic parking lots
Dynamic parking lots allow you to create new parking lots without having to reload the parking configuration. To use them you must enable the parkeddynamic option in the global section of res_parking.conf .
A dynamic parking lot is created when a channel tries to access an unknown parking lot. The new parking lot can use several channel variables to define the new parking lot. There is a channel variable to specify the template parking lot to use (PARKINGDYNAMIC ), the parkext option (PARKINGDYNEXTEN ), the parkpos option (PARKINGDYNPOS ), and the parking lot context option (PARKINGDYNCONTEXT ). All of these channel variables are optional. Unspecified and any other parking lot options come from the template parking lot. However, the new parking lot’s managed dialplan extensions cannot overlap any existing parking lot’s managed extensions.
Putting the pieces together
After examining the pieces of call parking lets put that knowledge to use by constructing some parking setups with a few parking lots.
Static setup for an organization
This example has a few non-overlapping parking lots in one context. I have made each parking lot slightly different to demonstrate how parking lots are selected by who does the parking and which parking lot access extension is used. The basic parking configuration in this example is more desirable with how you would want to setup for an organization where you have a parking lot for different departments like sales and manufacturing with a default lot for general or inter-department parking.
First we will create the alice, bob, charlie, david, and eddie endpoints for demonstration calls. Oh, and we’ll also create a pa_system endpoint to demonstrate ParkAndAnnounce.
[transport-udp] type=transport bind=0.0.0.0 protocol=udp [endpoint](!) type=endpoint allow=!all,ulaw context=internal [aor](!) type=aor max_contacts=1 [alice](endpoint) aors=alice [alice](aor) [bob](endpoint) aors=bob [bob](aor) [charlie](endpoint) aors=charlie set_var=CHANNEL(parkinglot)=custom_1 [charlie](aor) [david](endpoint) aors=david set_var=CHANNEL(parkinglot)=custom_2 [david](aor) [eddie](endpoint) aors=eddie set_var=CHANNEL(parkinglot)=custom_3 [eddie](aor) ; This endpoint needs to auto-answer, but for demonstration ; purposes you can manually answer it. [pa_system](endpoint) aors=pa_system [pa_system](aor)
Now lets create some static parking lots. We’ll create three custom parking lots and the default parking lot. Each parking lot is slightly different to demonstrate how general and exclusive parking lot access extensions behave.
[general] [lot](!) context=parkedcalls parkingtime=20 comebacktoorigin=no comebackcontext=parking_timeout [default](lot) parkext=700 parkpos=701-702 [custom_1](lot) ; We can set parkext to 700 and share the default parking lot ; access extension because the access extension is general and ; can access any parking lot. parkext=700 parkpos=711-712 [custom_2](lot) parkext=720 parkpos=721-722 parkinghints=yes [custom_3](lot) parkext=730 parkext_exclusive=yes parkpos=731-732
Now to create the dialplan since Asterisk isn’t much good without one.
[internal] exten=alice,1,NoOp() same=n,Dial(PJSIP/alice,20,TK) same=n,Hangup() exten=bob,1,NoOp() same=n,Dial(PJSIP/bob,20,tk) same=n,Hangup() exten=charlie,1,NoOp() same=n,Dial(PJSIP/charlie,20,tk) same=n,Hangup() exten=david,1,NoOp() same=n,Dial(PJSIP/david,20,tk) same=n,Hangup() exten=eddie,1,NoOp() same=n,Dial(PJSIP/eddie,20,tk) same=n,Hangup() exten=740,1,NoOp() same=n,ParkAndAnnounce(,,silence/1:call-waiting:letters/at:PARKED:auth-thankyou,PJSIP/pa_system) same=n,Hangup() include=parkedcalls [parking_timeout] exten=s,1,NoOp(Parked call channel that timed out: ${CHANNEL(name)}) same=n,Playback(vm-goodbye) same=n,Hangup() ; The following dialplan context is what Asterisk generates ; according to the parking lots defined in res_parking.conf. ;[parkedcalls] ;exten=700,1,Park() ;exten=701,1,ParkedCall(default,701) ;exten=702,1,ParkedCall(default,702) ; ;exten=711,1,ParkedCall(custom_1,711) ;exten=712,1,ParkedCall(custom_1,712) ; ;exten=720,1,Park() ;exten=721,hint,park:721@parkedcalls ;exten=721,1,ParkedCall(custom_2,721) ;exten=722,hint,park:722@parkedcalls ;exten=722,1,ParkedCall(custom_2,722) ; ;exten=730,1,Park(custom_3) ;exten=731,1,ParkedCall(custom_3,731) ;exten=732,1,ParkedCall(custom_3,732)
Now to illustrate how these parking lots work. All of the scenarios are basically the same. Alice will call someone who will perform an attended transfer to a parking lot access extension and leave her there until the 20 second timeout. At that point alice will hear “good-bye” and the call hangs up. Each scenario shows that alice can get parked in a different parking lot depending upon who parks her and which access extension is used. While alice is parked, she can be retrieved by anyone if they dial the parking space extension (701, 711, 721, or 731) she currently occupies.
Alice calls bob, charlie, david, or eddie. Then alice is attended transferred to the parking access extension 700, 720, 730, or 740. The table below shows which parking space alice enters.
| 700 | 720 | 730 | 740 ------------------------------- bob | 701 | 701 | 731 | 701 charlie | 711 | 711 | 731 | 711 david | 721 | 721 | 731 | 721 eddie | 731 | 731 | 731 | 731
Things to note:
- Transferring alice to a general parking access extension gets alice parked into different parking lots depending upon who transferred her.
- Transferring alice to 730 always parks alice in the custom_3 parking lot because that parking access extension is exclusively for custom_3 .
- When alice is parked in the custom_2 parking lot there are hints available to monitor if someone is in one of the parking lot’s spaces.
- When alice is transferred to 740, where alice gets parked is announced over a public-address system by ParkAndAnnounce when it dials PJSIP/pa_system .
Static setup for multi-tenant
This parking configuration is more desirable for a multi-tenant arrangement. Each tenant has their own parking lot and they are the only ones who can retrieve their parked calls.
First we will create the alice, bob, charlie, david, and eddie endpoints for demonstration calls.
[transport-udp] type=transport bind=0.0.0.0 protocol=udp [endpoint](!) type=endpoint allow=!all,ulaw context=internal [endpoint_tenant_1](!,endpoint) set_var=CHANNEL(parkinglot)=tenant_1 [endpoint_tenant_2](!,endpoint) set_var=CHANNEL(parkinglot)=tenant_2 [aor](!) type=aor max_contacts=1 [alice](endpoint) aors=alice [alice](aor) [bob](endpoint_tenant_1) aors=bob [bob](aor) [charlie](endpoint_tenant_1) aors=charlie [charlie](aor) [david](endpoint_tenant_2) aors=david [david](aor) [eddie](endpoint_tenant_2) aors=eddie [eddie](aor)
Now lets create a static parking lot for each tenant. The default parking lot is not needed. However, since it will always exist, we’ll set it up to bounce calls quickly back to whoever parked them.
[general] ; Anyone getting parked here got here in error because they ; are in an unclaimed parking lot. We'll park them briefly ; and try to send them back to whoever parked them. [default] context=parkedcalls parkext=700 parkpos=701 parkingtime=2 [lot](!) parkext=700 ; Make the parking access extension exclusive so one-touch ; parking will always go to this parking lot. Otherwise ; this access extension is not used. parkext_exclusive=yes parkpos=701-702 parkingtime=20 comebacktoorigin=no comebackcontext=parking_timeout [tenant_1](lot) context=park_tenant_1 [tenant_2](lot) context=park_tenant_2
Now to create the dialplan since Asterisk isn’t much good without one.
[internal] exten=alice,1,NoOp() same=n,Dial(PJSIP/alice,20,TK) same=n,Hangup() exten=bob,1,NoOp() same=n,Dial(PJSIP/bob,20,tk) same=n,Hangup() exten=charlie,1,NoOp() same=n,Dial(PJSIP/charlie,20,tk) same=n,Hangup() ; General parking access extension shared by all tenants. exten=700,Park() same=n,Hangup() ; General parking retrieval extensions shared by all tenants. exten=_70[1-2],ParkedCall(,${EXTEN}) same=n,Hangup() [parking_timeout] exten=s,1,NoOp(Parked call channel that timed out: ${CHANNEL(name)}) same=n,Playback(vm-goodbye) same=n,Hangup() ; The following dialplan context is what Asterisk generates ; according to the parking lots defined in res_parking.conf. ;[parkedcalls] ;exten=700,1,Park() ;exten=701,1,ParkedCall(default,701) ; ;[park_tenant_1] ;exten=700,1,Park(tenant_1) ;exten=701,1,ParkedCall(tenant_1,701) ;exten=702,1,ParkedCall(tenant_1,702) ; ;[park_tenant_2] ;exten=700,1,Park(tenant_2) ;exten=701,1,ParkedCall(tenant_2,701) ;exten=702,1,ParkedCall(tenant_2,702)
Now to see how these isolated tenant parking lots operate. If alice calls bob and he attended transfers her to 700 she will wind up in the tenant_1 parking lot at parking space 701. Only bob or charlie can retrieve alice because their endpoints are setup to access the tenant_1 parking lot. Similarly if alice calls david and he does the same thing then only david or eddie can retrieve alice.
Dynamic setup for multi-tenant
This is an equivalent setup to the “Static setup for multi-tenant” example above but using dynamically created parking lots. We just need to make some minor changes to the configuration files. For pjsip.conf we just change the definitions of the endpoint templates for the tenants. For res_parking.conf we enable dynamic parking lots and replace the static tenant parking lots with a parking lot to use as a template for the dynamic tenant parking lots.
[transport-udp] type=transport bind=0.0.0.0 protocol=udp [endpoint](!) type=endpoint allow=!all,ulaw context=internal [endpoint_tenant_base](!,endpoint) set_var=__PARKINGDYNAMIC=tenant_template set_var=__PARKINGDYNEXTEN=700 [endpoint_tenant_1](!,endpoint_tenant_base) set_var=__PARKINGDYNCONTEXT=park_tenant_1 set_var=CHANNEL(parkinglot)=tenant_1 [endpoint_tenant_2](!,endpoint_tenant_base) set_var=__PARKINGDYNCONTEXT=park_tenant_2 set_var=CHANNEL(parkinglot)=tenant_2 [aor](!) type=aor max_contacts=1 [alice](endpoint) aors=alice [alice](aor) [bob](endpoint_tenant_1) aors=bob [bob](aor) [charlie](endpoint_tenant_1) aors=charlie [charlie](aor) [david](endpoint_tenant_2) aors=david [david](aor) [eddie](endpoint_tenant_2) aors=eddie [eddie](aor)
[general] parkeddynamic=yes ; Anyone getting parked here got here in error because they ; are in an unclaimed parking lot. We'll park them briefly ; and try to send them back to whoever parked them. [default] context=parkedcalls parkext=700 parkpos=701 parkingtime=2 [tenant_template] ; We are intentionally not defining parkext to prevent ; creating unnecessary dialplan extensions for the parking ; lot. We are just using this parking lot as a template to ; create dynamic parking lots so we don't need the dialplan ; extensions. When a dynamic parking lot is created we will ; specify the parkext by setting the PARKINGDYNEXTEN channel ; variable. ; ; Make the parking access extension exclusive so one-touch ; parking will always go to this parking lot. Otherwise ; this access extension is not used. parkext_exclusive=yes parkpos=701-702 parkingtime=20 comebacktoorigin=no comebackcontext=parking_timeout
The dialplan in extensions.conf is the same as the “Static setup for multi-tenant” example. The only difference is the parking lots are dynamically generated the first time someone gets parked in the parking lot instead of when res_parking.so is loaded.
Just for fun
You could use Park to implement your own automatic call distribution queue. Callers call in and Park themselves in your queue parking lot. Your external queue program receives AMI parking events about the new arrivals and which parking space they were put in. Then your queue program determines if an agent is available to take a call and uses the AMI originate action to call the agent and execute the ParkedCall application to retrieve the queued caller.
One Response
that’s great tutorial.