aboutsummaryrefslogtreecommitdiffstats log msg author committer range
path: root/doc/sla.tex
blob: 735285e352e86a3f7d1365caf5828aaea17319b6 (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  pre { line-height: 125%; margin: 0; } td.linenos pre { color: #000000; background-color: #f0f0f0; padding: 0 5px 0 5px; } span.linenos { color: #000000; background-color: #f0f0f0; padding: 0 5px 0 5px; } td.linenos pre.special { color: #000000; background-color: #ffffc0; padding: 0 5px 0 5px; } span.linenos.special { color: #000000; background-color: #ffffc0; padding: 0 5px 0 5px; } .highlight .hll { background-color: #ffffcc } .highlight { background: #ffffff; } .highlight .c { color: #888888 } /* Comment */ .highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */ .highlight .k { color: #008800; font-weight: bold } /* Keyword */ .highlight .ch { color: #888888 } /* Comment.Hashbang */ .highlight .cm { color: #888888 } /* Comment.Multiline */ .highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */ .highlight .cpf { color: #888888 } /* Comment.PreprocFile */ .highlight .c1 { color: #888888 } /* Comment.Single */ .highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */ .highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ .highlight .ge { font-style: italic } /* Generic.Emph */ .highlight .gr { color: #aa0000 } /* Generic.Error */ .highlight .gh { color: #333333 } /* Generic.Heading */ .highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ .highlight .go { color: #888888 } /* Generic.Output */ .highlight .gp { color: #555555 } /* Generic.Prompt */ .highlight .gs { font-weight: bold } /* Generic.Strong */ .highlight .gu { color: #666666 } /* Generic.Subheading */ .highlight .gt { color: #aa0000 } /* Generic.Traceback */ .highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */ .highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */ .highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */ .highlight .kp { color: #008800 } /* Keyword.Pseudo */ .highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */ .highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */ .highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */ .highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */ .highlight .na { color: #336699 } /* Name.Attribute */ .highlight .nb { color: #003388 } /* Name.Builtin */ .highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */ .highlight .no { color: #003366; font-weight: bold } /* Name.Constant */ .highlight .nd { color: #555555 } /* Name.Decorator */ .highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */ .highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */ .highlight .nl { color: #336699; font-style: italic } /* Name.Label */ .highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */ .highlight .py { color: #336699; font-weight: bold } /* Name.Property */ .highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */ .highlight .nv { color: #336699 } /* Name.Variable */ .highlight .ow { color: #008800 } /* Operator.Word */ .highlight .w { color: #bbbbbb } /* Text.Whitespace */ .highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */ .highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */ .highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */ .highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */\documentclass[12pt,a4]{article} \usepackage{hyperref} \author{Russell Bryant \\ Software Engineer \\ Digium, Inc.} \title{Shared Line Appearances} \begin{document} \maketitle \tableofcontents \section{Introduction} The "SLA" functionality in Asterisk is intended to allow a setup that emulates a simple key system. It uses the various abstraction layers already built into Asterisk to emulate key system functionality across various devices, including IP channels. \section{Configuration} \subsection{Summary} An SLA system is built up of virtual trunks and stations mapped to real Asterisk devices. The configuration for all of this is done in three different files: extensions.conf, sla.conf, and the channel specific configuration file such as sip.conf or zapata.conf. \subsection{Dialplan} The SLA implementation can automatically generate the dialplan necessary for basic operation if the "autocontext" option is set for trunks and stations in sla.conf. However, for reference, here is an automatically generated dialplan to help with custom building of the dialplan to include other features, such as voicemail (\ref{voicemail}). However, note that there is a little bit of additional configuration needed if the trunk is an IP channel. This is discussed in the section on trunks (\ref{trunks}). There are extensions for incoming calls on a specific trunk, which execute the SLATrunk application, as well as incoming calls from a station, which execute SLAStation. Note that there are multiple extensions for incoming calls from a station. This is because the SLA system has to know whether the phone just went off hook, or if the user pressed a specific line button. Also note that there is a hint for every line on every station. This lets the SLA system control each individual light on every phone to ensure that it shows the correct state of the line. The phones must subscribe to the state of each of their line appearances. \begin{verbatim} [line1] exten => s,1,SLATrunk(line1) [line2] exten => s,2,SLATrunk(line2) [sla_stations] exten => station1,1,SLAStation(station1) exten => station1_line1,hint,SLA:station1_line1 exten => station1_line1,1,SLAStation(station1_line1) exten => station1_line2,hint,SLA:station1_line2 exten => station1_line2,1,SLAStation(station1_line2) exten => station2,1,SLAStation(station2) exten => station2_line1,hint,SLA:station2_line1 exten => station2_line1,1,SLAStation(station2_line1) exten => station2_line2,hint,SLA:station2_line2 exten => station2_line2,1,SLAStation(station2_line2) exten => station3,1,SLAStation(station3) exten => station3_line1,hint,SLA:station3_line1 exten => station3_line1,1,SLAStation(station3_line1) exten => station3_line2,hint,SLA:station3_line2 exten => station3_line2,1,SLAStation(station3_line2) \end{verbatim} \subsection{Trunks} \label{trunks} An SLA trunk is a mapping between a virtual trunk and a real Asterisk device. This device may be an analog FXO line, or something like a SIP trunk. A trunk must be configured in two places. First, configure the device itself in the channel specific configuration file such as zapata.conf or sip.conf. Once the trunk is configured, then map it to an SLA trunk in sla.conf. \begin{verbatim} [line1] type=trunk device=Zap/1 \end{verbatim} Be sure to configure the trunk's context to be the same one that is set for the "autocontext" option in sla.conf if automatic dialplan configuration is used. This would be done in the regular device entry in zapata.conf, sip.conf, etc. Note that the automatic dialplan generation creates the SLATrunk() extension at extension 's'. This is perfect for Zap channels that are FXO trunks, for example. However, it may not be good enough for an IP trunk, since the call coming in over the trunk may specify an actual number. If the dialplan is being built manually, ensure that calls coming in on a trunk execute the SLATrunk() application with an argument of the trunk name, as shown in the dialplan example before. IP trunks can be used, but they require some additional configuration to work. For this example, let's say we have a SIP trunk called "mytrunk" that is going to be used as line4. Furthermore, when calls come in on this trunk, they are going to say that they are calling the number "12564286000". Also, let's say that the numbers that are valid for calling out this trunk are NANP numbers, of the form \_1NXXNXXXXXX. In sip.conf, there would be an entry for [mytrunk]. For [mytrunk], set context=line4. \begin{verbatim} [line4] type=trunk device=Local/disa@line4_outbound \end{verbatim} \begin{verbatim} [line4] exten => 12564286000,1,SLATrunk(line4) [line4_outbound] exten => disa,1,Disa(no-password|line4_outbound) exten => _1NXXNXXXXXX,1,Dial(SIP/\${EXTEN}@mytrunk) \end{verbatim} So, when a station picks up their phone and connects to line 4, they are connected to the local dialplan. The Disa application plays dialtone to the phone and collects digits until it matches an extension. In this case, once the phone dials a number like 12565551212, the call will proceed out the SIP trunk. \subsection{Stations} An SLA station is a mapping between a virtual station and a real Asterisk device. Currently, the only channel driver that has all of the features necessary to support an SLA environment is chan\_sip. So, to configure a SIP phone to use as a station, you must configure sla.conf and sip.conf. \begin{verbatim} [station1] type=station device=SIP/station1 trunk=line1 trunk=line2 \end{verbatim} Here are some hints on configuring a SIP phone for use with SLA: \begin{enumerate} \item Add the SIP channel as a [station] in sla.conf. \item Configure the phone in sip.conf. If automatic dialplan configuration was used by enabling the "autocontext" option in sla.conf, then this entry in sip.conf should have the same context setting. \item On the phone itself, there are various things that must be configured to make everything work correctly: Let's say this phone is called "station1" in sla.conf, and it uses trunks named "line1" and line2". \begin{enumerate} \item Two line buttons must be configured to subscribe to the state of the following extensions: - station1\_line1 - station1\_line2 \item The line appearance buttons should be configured to dial the extensions that they are subscribed to when they are pressed. \item If you would like the phone to automatically connect to a trunk when it is taken off hook, then the phone should be automatically configured to dial "station1" when it is taken off hook. \end{enumerate} \end{enumerate} \section{Configuration Examples} \subsection{SLA and Voicemail} \label{voicemail} This is an example of how you could set up a single voicemail box for the phone system. The voicemail box number used in this example is 1234, which would be configured in voicemail.conf. For this example, assume that there are 2 trunks and 3 stations. The trunks are Zap/1 and Zap/2. The stations are SIP/station1, SIP/station2, and SIP/station3. In zapata.conf, channel 1 has context=line1 and channel 2 has context=line2. In sip.conf, all three stations are configured with context=sla\_stations. When the stations pick up their phones to dial, they are allowed to dial NANP numbers for outbound calls, or 8500 for checking voicemail. sla.conf: \begin{verbatim} [line1] type=trunk device=Local/disa@line1_outbound [line2] type=trunk device=Local/disa@line2_outbound [station](!) type=station trunk=line1 trunk=line2 [station1](station) device=SIP/station1 [station2](station) device=SIP/station2 [station3](station) device=SIP/station3 \end{verbatim} extensions.conf: \begin{verbatim} [macro-slaline] exten => s,1,SLATrunk(${ARG1}) exten => s,n,Goto(s-${SLATRUNK_STATUS}|1) exten => s-FAILURE,1,Voicemail(1234|u) exten => s-UNANSWERED,1,Voicemail(1234|u) [line1] exten => s,1,Macro(slaline|line1) [line2] exten => s,2,Macro(slaline|line2) [line1_outbound] exten => disa,1,Disa(no-password|line1_outbound) exten => _1NXXNXXXXXX,1,Dial(Zap/1/${EXTEN}) exten => 8500,1,VoicemailMain(1234) [line2_outbound] exten => disa,1,Disa(no-password|line2_outbound) exten => _1NXXNXXXXXX,1,Dial(Zap/2/\${EXTEN}) exten => 8500,1,VoicemailMain(1234) [sla_stations] exten => station1,1,SLAStation(station1) exten => station1_line1,hint,SLA:station1_line1 exten => station1_line1,1,SLAStation(station1_line1) exten => station1_line2,hint,SLA:station1_line2 exten => station1_line2,1,SLAStation(station1_line2) exten => station2,1,SLAStation(station2) exten => station2_line1,hint,SLA:station2_line1 exten => station2_line1,1,SLAStation(station2_line1) exten => station2_line2,hint,SLA:station2_line2 exten => station2_line2,1,SLAStation(station2_line2) exten => station3,1,SLAStation(station3) exten => station3_line1,hint,SLA:station3_line1 exten => station3_line1,1,SLAStation(station3_line1) exten => station3_line2,hint,SLA:station3_line2 exten => station3_line2,1,SLAStation(station3_line2) \end{verbatim} \section{Call Handling} \subsection{Summary} This section is intended to describe how Asterisk handles calls inside of the SLA system so that it is clear what behavior is expected. Note that this section is not yet complete. \subsection{Station goes off hook (not ringing)} When a station goes off hook, it should initiate a call to Asterisk with the extension that indicates that the phone went off hook without specifying a specific line. In the examples in this document, for the station named "station1", this extension is simply named, "station1". Asterisk will attempt to connect this station to the first available trunk that is not in use. Asterisk will check the trunks in the order that they were specified in the station entry in sla.conf. If all trunks are in use, the call will be denied. If Asterisk is able to acquire an idle trunk for this station, then trunk is connected to the station and the station will hear dialtone. The station can then proceed to dial a number to call. As soon as a trunk is acquired, all appearances of this line on stations will show that the line is in use. \subsection{Station goes off hook (ringing)} When a station goes off hook while it is ringing, it should simply answer the call that had been initiated to it to make it ring. Once the station has answered, Asterisk will figure out which trunk to connect it to. It will connect it to the highest priority trunk that is currently ringing. Trunk priority is determined by the order that the trunks are listed in the station entry in sla.conf. \subsection{Line button on a station is pressed} When a line button is pressed on a station, the station should initiate a call to Asterisk with the extension that indicates which line button was pressed. In the examples given in this document, for a station named "station1" and a trunk named "line1", the extension would be "station1\_line1". If the specified trunk is not in use, then the station will be connected to it and will hear dialtone. All appearances of this trunk will then show that it is now in use. If the specified trunk is on hold by this station, then this station will be reconnected to the trunk. The line appearance for this trunk on this station will now show in use. If this was the only station that had the call on hold, then all appearances of this trunk will now show that it is in use. Otherwise, all stations that are not currently connected to this trunk will show it on hold. If the specified trunk is on hold by a different station, then this station will be connected to the trunk only if the trunk itself and the station(s) that have it on hold do not have private hold enabled. If connected, the appeareance of this trunk on this station will then show in use. All stations that are not currently connected to this trunk will show it on hold. \end{document}