staskobzar /
goagi
| 1 | package goagi |
||
| 2 | |||
| 3 | import ( |
||
| 4 | "fmt" |
||
| 5 | ) |
||
| 6 | |||
| 7 | // Command sends command as string to the AGI and returns response valus with |
||
| 8 | // text response |
||
| 9 | func (agi *AGI) Command(cmd string) (Response, error) { |
||
| 10 | return agi.execute(cmd + "\n") |
||
| 11 | } |
||
| 12 | |||
| 13 | // Answer executes AGI command "ANSWER" |
||
| 14 | // Answers channel if not already in answer state. |
||
| 15 | func (agi *AGI) Answer() (Response, error) { |
||
| 16 | return agi.execute("ANSWER\n") |
||
| 17 | } |
||
| 18 | |||
| 19 | // AsyncAGIBreak Interrupts Async AGI |
||
| 20 | // Interrupts expected flow of Async AGI commands and returns control |
||
| 21 | // to previous source (typically, the PBX dialplan). |
||
| 22 | func (agi *AGI) AsyncAGIBreak() (Response, error) { |
||
| 23 | return agi.execute("ASYNCAGI BREAK\n") |
||
| 24 | } |
||
| 25 | |||
| 26 | /* |
||
| 27 | ChannelStatus returns status of the connected channel. |
||
| 28 | |||
| 29 | If no channel name is given (empty line) then returns the status of the current channel. |
||
| 30 | |||
| 31 | Return values: |
||
| 32 | |||
| 33 | 0 - Channel is down and available. |
||
| 34 | |||
| 35 | 1 - Channel is down, but reserved. |
||
| 36 | |||
| 37 | 2 - Channel is off hook. |
||
| 38 | |||
| 39 | 3 - Digits (or equivalent) have been dialed. |
||
| 40 | |||
| 41 | 4 - Line is ringing. |
||
| 42 | |||
| 43 | 5 - Remote end is ringing. |
||
| 44 | |||
| 45 | 6 - Line is up. |
||
| 46 | |||
| 47 | 7 - Line is busy. |
||
| 48 | */ |
||
| 49 | func (agi *AGI) ChannelStatus(channel string) (Response, error) { |
||
| 50 | cmd := fmt.Sprintf("CHANNEL STATUS %s\n", channel) |
||
| 51 | return agi.execute(cmd) |
||
| 52 | } |
||
| 53 | |||
| 54 | /* |
||
| 55 | ControlStreamFile sends audio file on channel and allows the listener to control the stream. |
||
| 56 | Send the given file, allowing playback to be controlled by the given digits, if any. |
||
| 57 | Use double quotes for the digits if you wish none to be permitted. If offsetms |
||
| 58 | is provided then the audio will seek to offsetms before play starts. |
||
| 59 | |||
| 60 | Example: |
||
| 61 | |||
| 62 | agi.ControlStreamFile("prompt_en", "19", "3000", "#", "0", "#", "1600") |
||
| 63 | agi.ControlStreamFile("prompt_en", "") |
||
| 64 | agi.ControlStreamFile("prompt_en", "19", "", "", "", "#", "1600") |
||
| 65 | |||
| 66 | */ |
||
| 67 | func (agi *AGI) ControlStreamFile(filename, digits string, args ...string) (Response, error) { |
||
| 68 | cmd := fmt.Sprintf("CONTROL STREAM FILE %s %q", filename, digits) |
||
| 69 | |||
| 70 | if len(args) > 5 { |
||
| 71 | return nil, ErrAGI.Msg("Too many arguments. Unknown args: %v", args[5:]) |
||
| 72 | } |
||
| 73 | |||
| 74 | for _, v := range args { |
||
| 75 | cmd = fmt.Sprintf("%s %q", cmd, v) |
||
| 76 | } |
||
| 77 | |||
| 78 | cmd = fmt.Sprintf("%s\n", cmd) |
||
| 79 | return agi.execute(cmd) |
||
| 80 | } |
||
| 81 | |||
| 82 | // DatabaseDel deletes an entry in the Asterisk database for a given family and key. |
||
| 83 | // Returns status and error if fails. |
||
| 84 | func (agi *AGI) DatabaseDel(family, key string) (Response, error) { |
||
| 85 | cmd := fmt.Sprintf("DATABASE DEL %s %s\n", family, key) |
||
| 86 | return agi.execute(cmd) |
||
| 87 | } |
||
| 88 | |||
| 89 | // DatabaseDelTree deletes a family or specific keytree within a family in the Asterisk database. |
||
| 90 | func (agi *AGI) DatabaseDelTree(family, keytree string) (Response, error) { |
||
| 91 | cmd := fmt.Sprintf("DATABASE DELTREE %s %s\n", family, keytree) |
||
| 92 | return agi.execute(cmd) |
||
| 93 | } |
||
| 94 | |||
| 95 | // DatabaseGet Retrieves an entry in the Asterisk database for a given family and key. |
||
| 96 | // Returns value as string or error if failed or value not set |
||
| 97 | // Response.Value() for result |
||
| 98 | func (agi *AGI) DatabaseGet(family, key string) (Response, error) { |
||
| 99 | cmd := fmt.Sprintf("DATABASE GET %s %s\n", family, key) |
||
| 100 | return agi.execute(cmd) |
||
| 101 | } |
||
| 102 | |||
| 103 | // DatabasePut adds or updates an entry in the Asterisk database for |
||
| 104 | // a given family, key, and value. |
||
| 105 | func (agi *AGI) DatabasePut(family, key, val string) (Response, error) { |
||
| 106 | cmd := fmt.Sprintf("DATABASE PUT %s %s %s\n", family, key, val) |
||
| 107 | return agi.execute(cmd) |
||
| 108 | } |
||
| 109 | |||
| 110 | // Exec executes application with given options. |
||
| 111 | func (agi *AGI) Exec(app, opts string) (Response, error) { |
||
| 112 | cmd := fmt.Sprintf("EXEC %s %q\n", app, opts) |
||
| 113 | return agi.execute(cmd) |
||
| 114 | } |
||
| 115 | |||
| 116 | /* |
||
| 117 | GetData Stream the given file, and receive DTMF data. |
||
| 118 | Note: when timeout is 0 then Asterisk will use 6 secods. |
||
| 119 | Note: Asterisk has strange way to handle get data response. |
||
| 120 | Contrary to other responses, where result has numeric value, |
||
| 121 | here asterisk puts DTMF to sent by user to result and this value |
||
| 122 | may contain "#" and "*". |
||
| 123 | |||
| 124 | To get DTMF sent by user use Response.Data() |
||
| 125 | |||
| 126 | Response.Value() will contain "timeout" if user has not terminated |
||
| 127 | input with "#" |
||
| 128 | */ |
||
| 129 | func (agi *AGI) GetData(file string, timeout, maxdigit int) (Response, error) { |
||
| 130 | cmd := fmt.Sprintf("GET DATA %s %d %d\n", file, timeout, maxdigit) |
||
| 131 | resp, err := agi.execute(cmd) |
||
| 132 | if err != nil { |
||
| 133 | return nil, err |
||
| 134 | } |
||
| 135 | // special get data result treatment |
||
| 136 | if resp.Result() == -1 || resp.Code() != codeSucc { |
||
| 137 | return resp, nil |
||
| 138 | } |
||
| 139 | |||
| 140 | r := resp.(*responseSuccess) |
||
| 141 | r.result = 0 |
||
| 142 | r.data = scanResultStrFromRaw(r.raw) |
||
| 143 | return r, nil |
||
| 144 | } |
||
| 145 | |||
| 146 | // GetFullVariable evaluates a channel expression |
||
| 147 | func (agi *AGI) GetFullVariable(name, channel string) (Response, error) { |
||
| 148 | cmd := "GET FULL VARIABLE" |
||
| 149 | if channel == "" { |
||
| 150 | cmd = fmt.Sprintf("%s %s\n", cmd, name) |
||
| 151 | } else { |
||
| 152 | cmd = fmt.Sprintf("%s %s %s\n", cmd, name, channel) |
||
| 153 | } |
||
| 154 | return agi.execute(cmd) |
||
| 155 | } |
||
| 156 | |||
| 157 | // GetOption Stream file, prompt for DTMF, with timeout. |
||
| 158 | // Behaves similar to STREAM FILE but used with a timeout option. |
||
| 159 | // Returns digit pressed, offset and error |
||
| 160 | func (agi *AGI) GetOption(filename, digits string, timeout int32) (Response, error) { |
||
| 161 | cmd := fmt.Sprintf("GET OPTION %s %q %d\n", filename, digits, timeout) |
||
| 162 | return agi.execute(cmd) |
||
| 163 | } |
||
| 164 | |||
| 165 | // GetVariable Gets a channel variable. |
||
| 166 | func (agi *AGI) GetVariable(name string) (Response, error) { |
||
| 167 | cmd := fmt.Sprintf("GET VARIABLE %s\n", name) |
||
| 168 | return agi.execute(cmd) |
||
| 169 | } |
||
| 170 | |||
| 171 | // Hangs up the specified channel. If no channel name is given, hangs up the current channel |
||
|
0 ignored issues
–
show
introduced
by
Loading history...
|
|||
| 172 | func (agi *AGI) Hangup(channel ...string) (Response, error) { |
||
| 173 | cmd := "HANGUP" |
||
| 174 | |||
| 175 | if len(channel) > 0 { |
||
| 176 | cmd = fmt.Sprintf("%s %s\n", cmd, channel[0]) |
||
| 177 | } else { |
||
| 178 | cmd = fmt.Sprintf("%s\n", cmd) |
||
| 179 | } |
||
| 180 | return agi.execute(cmd) |
||
| 181 | } |
||
| 182 | |||
| 183 | /* |
||
| 184 | ReceiveChar Receives one character from channels supporting it. |
||
| 185 | Most channels do not support the reception of text. Returns the decimal value of |
||
| 186 | the character if one is received, or 0 if the channel does not support text reception. |
||
| 187 | |||
| 188 | timeout - The maximum time to wait for input in milliseconds, or 0 for infinite. |
||
| 189 | |||
| 190 | Returns result -1 on error or char byte |
||
| 191 | */ |
||
| 192 | func (agi *AGI) ReceiveChar(timeout int) (Response, error) { |
||
| 193 | cmd := fmt.Sprintf("RECEIVE CHAR %d\n", timeout) |
||
| 194 | return agi.execute(cmd) |
||
| 195 | } |
||
| 196 | |||
| 197 | /* |
||
| 198 | ReceiveText Receives text from channels supporting it. |
||
| 199 | |||
| 200 | timeout - The timeout to be the maximum time to wait for input in milliseconds, or 0 for infinite. |
||
| 201 | */ |
||
| 202 | func (agi *AGI) ReceiveText(timeout int) (Response, error) { |
||
| 203 | cmd := fmt.Sprintf("RECEIVE TEXT %d\n", timeout) |
||
| 204 | return agi.execute(cmd) |
||
| 205 | } |
||
| 206 | |||
| 207 | /* |
||
| 208 | RecordFile Record to a file until a given dtmf digit in the sequence is received. |
||
| 209 | The format will specify what kind of file will be recorded. The timeout is the |
||
| 210 | maximum record time in milliseconds, or -1 for no timeout. |
||
| 211 | |||
| 212 | offset samples is optional, and, if provided, will seek to the offset without |
||
| 213 | exceeding the end of the file. |
||
| 214 | |||
| 215 | beep causes Asterisk to play a beep to the channel that is about to be recorded. |
||
| 216 | |||
| 217 | silence is the number of seconds of silence allowed before the function returns |
||
| 218 | despite the lack of dtmf digits or reaching timeout. |
||
| 219 | |||
| 220 | silence is the number of seconds of silence that are permitted before the |
||
| 221 | recording is terminated, regardless of the escape_digits or timeout arguments |
||
| 222 | |||
| 223 | If interupted by DTMF, digits will be available in Response.Data() |
||
| 224 | */ |
||
| 225 | func (agi *AGI) RecordFile(file, format, escDigits string, |
||
| 226 | timeout, offset int, beep bool, silence int) (Response, error) { |
||
| 227 | |||
| 228 | cmd := "RECORD FILE" |
||
| 229 | cmd = fmt.Sprintf("%s %s %s %q %d", cmd, file, format, escDigits, timeout) |
||
| 230 | if offset > 0 { |
||
| 231 | cmd = fmt.Sprintf("%s %d", cmd, offset) |
||
| 232 | } |
||
| 233 | if beep { |
||
| 234 | cmd = fmt.Sprintf("%s BEEP", cmd) |
||
| 235 | } |
||
| 236 | if silence > 0 { |
||
| 237 | cmd = fmt.Sprintf("%s s=%d", cmd, silence) |
||
| 238 | } |
||
| 239 | cmd = fmt.Sprintf("%s\n", cmd) |
||
| 240 | |||
| 241 | resp, err := agi.execute(cmd) |
||
| 242 | if err != nil { |
||
| 243 | return nil, err |
||
| 244 | } |
||
| 245 | |||
| 246 | if resp.Value() != "dtmf" { |
||
| 247 | return resp, nil |
||
| 248 | } |
||
| 249 | |||
| 250 | r := resp.(*responseSuccess) |
||
| 251 | r.result = 1 |
||
| 252 | r.data = scanResultStrFromRaw(r.raw) |
||
| 253 | |||
| 254 | return r, nil |
||
| 255 | } |
||
| 256 | |||
| 257 | // SayAlpha says a given character string, returning early if any of the given |
||
| 258 | // DTMF digits are received on the channel. |
||
| 259 | func (agi *AGI) SayAlpha(number, escDigits string) (Response, error) { |
||
| 260 | cmd := fmt.Sprintf("SAY ALPHA %s %q\n", number, escDigits) |
||
| 261 | return agi.execute(cmd) |
||
| 262 | } |
||
| 263 | |||
| 264 | // SayDate say a given date, returning early if any of the given DTMF digits |
||
| 265 | // are received on the channel |
||
| 266 | func (agi *AGI) SayDate(date, escDigits string) (Response, error) { |
||
| 267 | cmd := fmt.Sprintf("SAY DATE %s %q\n", date, escDigits) |
||
| 268 | return agi.execute(cmd) |
||
| 269 | } |
||
| 270 | |||
| 271 | // SayDatetime say a given time, returning early if any of the given DTMF |
||
| 272 | // digits are received on the channel |
||
| 273 | func (agi *AGI) SayDatetime(time, escDigits, format, timezone string) (Response, error) { |
||
| 274 | cmd := fmt.Sprintf("SAY DATETIME %s %q %q %q\n", time, escDigits, format, timezone) |
||
| 275 | return agi.execute(cmd) |
||
| 276 | } |
||
| 277 | |||
| 278 | // SayDigits say a given digit string, returning early if any of the given |
||
| 279 | // DTMF digits are received on the channel |
||
| 280 | func (agi *AGI) SayDigits(number, escDigits string) (Response, error) { |
||
| 281 | cmd := fmt.Sprintf("SAY DIGITS %s %q\n", number, escDigits) |
||
| 282 | return agi.execute(cmd) |
||
| 283 | } |
||
| 284 | |||
| 285 | // SayNumber say a given digit string, returning early if any of the given |
||
| 286 | // DTMF digits are received on the channel |
||
| 287 | func (agi *AGI) SayNumber(number, escDigits string) (Response, error) { |
||
| 288 | cmd := fmt.Sprintf("SAY NUMBER %s %q\n", number, escDigits) |
||
| 289 | return agi.execute(cmd) |
||
| 290 | } |
||
| 291 | |||
| 292 | // SayPhonetic say a given character string with phonetics, returning early |
||
| 293 | // if any of the given DTMF digits are received on the channel |
||
| 294 | func (agi *AGI) SayPhonetic(str, escDigits string) (Response, error) { |
||
| 295 | cmd := fmt.Sprintf("SAY PHONETIC %s %q\n", str, escDigits) |
||
| 296 | return agi.execute(cmd) |
||
| 297 | } |
||
| 298 | |||
| 299 | // SayTime say a given time, returning early if any of the given DTMF digits |
||
| 300 | // are received on the channel |
||
| 301 | func (agi *AGI) SayTime(time, escDigits string) (Response, error) { |
||
| 302 | cmd := fmt.Sprintf("SAY TIME %s %q\n", time, escDigits) |
||
| 303 | return agi.execute(cmd) |
||
| 304 | } |
||
| 305 | |||
| 306 | // SendImage Sends the given image on a channel. Most channels do not support |
||
| 307 | // the transmission of images. |
||
| 308 | func (agi *AGI) SendImage(image string) (Response, error) { |
||
| 309 | cmd := fmt.Sprintf("SEND IMAGE %q\n", image) |
||
| 310 | return agi.execute(cmd) |
||
| 311 | } |
||
| 312 | |||
| 313 | // SendText Sends the given text on a channel. Most channels do not support |
||
| 314 | // the transmission of text. |
||
| 315 | func (agi *AGI) SendText(text string) (Response, error) { |
||
| 316 | cmd := fmt.Sprintf("SEND TEXT %q\n", text) |
||
| 317 | return agi.execute(cmd) |
||
| 318 | } |
||
| 319 | |||
| 320 | // SetAutoHangup Cause the channel to automatically hangup at time seconds in the future. |
||
| 321 | // Setting to 0 will cause the autohangup feature to be disabled on this channel. |
||
| 322 | func (agi *AGI) SetAutoHangup(seconds int) (Response, error) { |
||
| 323 | cmd := fmt.Sprintf("SET AUTOHANGUP %d\n", seconds) |
||
| 324 | return agi.execute(cmd) |
||
| 325 | } |
||
| 326 | |||
| 327 | // SetCallerid Changes the callerid of the current channel. |
||
| 328 | func (agi *AGI) SetCallerid(clid string) (Response, error) { |
||
| 329 | cmd := fmt.Sprintf("SET CALLERID %q\n", clid) |
||
| 330 | return agi.execute(cmd) |
||
| 331 | } |
||
| 332 | |||
| 333 | // SetContext Sets the context for continuation upon exiting the application. |
||
| 334 | func (agi *AGI) SetContext(ctx string) (Response, error) { |
||
| 335 | cmd := fmt.Sprintf("SET CONTEXT %s\n", ctx) |
||
| 336 | return agi.execute(cmd) |
||
| 337 | } |
||
| 338 | |||
| 339 | // SetExtension Changes the extension for continuation upon exiting the application. |
||
| 340 | func (agi *AGI) SetExtension(ext string) (Response, error) { |
||
| 341 | cmd := fmt.Sprintf("SET EXTENSION %s\n", ext) |
||
| 342 | return agi.execute(cmd) |
||
| 343 | } |
||
| 344 | |||
| 345 | // SetMusic Enables/Disables the music on hold generator. If class is not specified, |
||
| 346 | // then the default music on hold class will be used. |
||
| 347 | func (agi *AGI) SetMusic(enable bool, class string) (Response, error) { |
||
| 348 | cmd := "SET MUSIC" |
||
| 349 | |||
| 350 | if enable { |
||
| 351 | cmd = fmt.Sprintf("%s on", cmd) |
||
| 352 | } else { |
||
| 353 | cmd = fmt.Sprintf("%s off", cmd) |
||
| 354 | } |
||
| 355 | |||
| 356 | cmd = fmt.Sprintf("%s %q\n", cmd, class) |
||
| 357 | return agi.execute(cmd) |
||
| 358 | } |
||
| 359 | |||
| 360 | // SetPriority Changes the priority for continuation upon exiting the application. |
||
| 361 | // The priority must be a valid priority or label. |
||
| 362 | func (agi *AGI) SetPriority(priority string) (Response, error) { |
||
| 363 | cmd := fmt.Sprintf("SET PRIORITY %s\n", priority) |
||
| 364 | return agi.execute(cmd) |
||
| 365 | } |
||
| 366 | |||
| 367 | // SetVariable Sets a variable to the current channel. |
||
| 368 | func (agi *AGI) SetVariable(name, value string) (Response, error) { |
||
| 369 | cmd := fmt.Sprintf("SET VARIABLE %s %q\n", name, value) |
||
| 370 | return agi.execute(cmd) |
||
| 371 | } |
||
| 372 | |||
| 373 | // StreamFile Send the given file, allowing playback to be interrupted by the given |
||
| 374 | // digits, if any. |
||
| 375 | func (agi *AGI) StreamFile(file, escDigits string, offset int) (Response, error) { |
||
| 376 | cmd := fmt.Sprintf("STREAM FILE %s %q %d\n", file, escDigits, offset) |
||
| 377 | return agi.execute(cmd) |
||
| 378 | } |
||
| 379 | |||
| 380 | // TDDMode Enable/Disable TDD transmission/reception on a channel. |
||
| 381 | // Modes: on, off, mate, tdd |
||
| 382 | func (agi *AGI) TDDMode(mode string) (Response, error) { |
||
| 383 | cmd := "TDD MODE" |
||
| 384 | switch mode { |
||
| 385 | case "on", "off", "mate", "tdd": |
||
| 386 | cmd = fmt.Sprintf("%s %s\n", cmd, mode) |
||
| 387 | default: |
||
| 388 | cmd = fmt.Sprintf("%s off\n", cmd) |
||
| 389 | } |
||
| 390 | return agi.execute(cmd) |
||
| 391 | } |
||
| 392 | |||
| 393 | // Verbose Sends message to the console via verbose message system. |
||
| 394 | // level is the verbose level (1-4) |
||
| 395 | func (agi *AGI) Verbose(msg string, level ...int) (Response, error) { |
||
| 396 | cmd := fmt.Sprintf("VERBOSE %q", msg) |
||
| 397 | lvl := 1 |
||
| 398 | if level != nil { |
||
| 399 | if level[0] > 0 && level[0] < 5 { |
||
| 400 | lvl = level[0] |
||
| 401 | } |
||
| 402 | } |
||
| 403 | cmd = fmt.Sprintf("%s %d\n", cmd, lvl) |
||
| 404 | return agi.execute(cmd) |
||
| 405 | } |
||
| 406 | |||
| 407 | /* |
||
| 408 | WaitForDigit Waits up to timeout *milliseconds* for channel to receive a DTMF digit. |
||
| 409 | Use -1 for the timeout value if you desire the call to block indefinitely. |
||
| 410 | |||
| 411 | Return digit pressed as string or error |
||
| 412 | */ |
||
| 413 | func (agi *AGI) WaitForDigit(timeout int) (Response, error) { |
||
| 414 | cmd := fmt.Sprintf("WAIT FOR DIGIT %d\n", timeout) |
||
| 415 | return agi.execute(cmd) |
||
| 416 | } |
||
| 417 |