github.com/CyCoreSystems/ari@v4.8.4+incompatible/channel.go (about) 1 package ari 2 3 import ( 4 "encoding/json" 5 "strings" 6 "time" 7 8 ptypes "github.com/gogo/protobuf/types" 9 "github.com/pkg/errors" 10 ) 11 12 // Channel represents a communication path interacting with an Asterisk server. 13 type Channel interface { 14 // Get returns a handle to a channel for further interaction 15 Get(key *Key) *ChannelHandle 16 17 // GetVariable retrieves the value of a channel variable 18 GetVariable(*Key, string) (string, error) 19 20 // List lists the channels in asterisk, optionally using the key for filtering 21 List(*Key) ([]*Key, error) 22 23 // Originate creates a new channel, returning a handle to it or an error, if 24 // the creation failed. 25 // The Key should be that of the linked channel, if one exists, so that the 26 // Node can be matches to it. 27 Originate(*Key, OriginateRequest) (*ChannelHandle, error) 28 29 // StageOriginate creates a new Originate, created when the `Exec` method 30 // on `ChannelHandle` is invoked. 31 // The Key should be that of the linked channel, if one exists, so that the 32 // Node can be matches to it. 33 StageOriginate(*Key, OriginateRequest) (*ChannelHandle, error) 34 35 // Create creates a new channel, returning a handle to it or an 36 // error, if the creation failed. Create is already Staged via `Dial`. 37 // The Key should be that of the linked channel, if one exists, so that the 38 // Node can be matches to it. 39 Create(*Key, ChannelCreateRequest) (*ChannelHandle, error) 40 41 // Data returns the channel data for a given channel 42 Data(key *Key) (*ChannelData, error) 43 44 // Continue tells Asterisk to return a channel to the dialplan 45 Continue(key *Key, context, extension string, priority int) error 46 47 // Busy hangs up the channel with the "busy" cause code 48 Busy(key *Key) error 49 50 // Congestion hangs up the channel with the "congestion" cause code 51 Congestion(key *Key) error 52 53 // Answer answers the channel 54 Answer(key *Key) error 55 56 // Hangup hangs up the given channel 57 Hangup(key *Key, reason string) error 58 59 // Ring indicates ringing to the channel 60 Ring(key *Key) error 61 62 // StopRing stops ringing on the channel 63 StopRing(key *Key) error 64 65 // SendDTMF sends DTMF to the channel 66 SendDTMF(key *Key, dtmf string, opts *DTMFOptions) error 67 68 // Hold puts the channel on hold 69 Hold(key *Key) error 70 71 // StopHold retrieves the channel from hold 72 StopHold(key *Key) error 73 74 // Mute mutes a channel in the given direction (in,out,both) 75 Mute(key *Key, dir Direction) error 76 77 // Unmute unmutes a channel in the given direction (in,out,both) 78 Unmute(key *Key, dir Direction) error 79 80 // MOH plays music on hold 81 MOH(key *Key, moh string) error 82 83 // SetVariable sets a channel variable 84 SetVariable(key *Key, name, value string) error 85 86 // StopMOH stops music on hold 87 StopMOH(key *Key) error 88 89 // Silence plays silence to the channel 90 Silence(key *Key) error 91 92 // StopSilence stops the silence on the channel 93 StopSilence(key *Key) error 94 95 // Play plays the media URI to the channel 96 Play(key *Key, playbackID string, mediaURI string) (*PlaybackHandle, error) 97 98 // StagePlay stages a `Play` operation and returns the `PlaybackHandle` 99 // for invoking it. 100 StagePlay(key *Key, playbackID string, mediaURI string) (*PlaybackHandle, error) 101 102 // Record records the channel 103 Record(key *Key, name string, opts *RecordingOptions) (*LiveRecordingHandle, error) 104 105 // StageRecord stages a `Record` operation and returns the `PlaybackHandle` 106 // for invoking it. 107 StageRecord(key *Key, name string, opts *RecordingOptions) (*LiveRecordingHandle, error) 108 109 // Dial dials a created channel 110 Dial(key *Key, caller string, timeout time.Duration) error 111 112 // Snoop spies on a specific channel, creating a new snooping channel 113 Snoop(key *Key, snoopID string, opts *SnoopOptions) (*ChannelHandle, error) 114 115 // StageSnoop creates a new `ChannelHandle`, when `Exec`ed, snoops on the given channel ID and 116 // creates a new snooping channel. 117 StageSnoop(key *Key, snoopID string, opts *SnoopOptions) (*ChannelHandle, error) 118 119 // Subscribe subscribes on the channel events 120 Subscribe(key *Key, n ...string) Subscription 121 } 122 123 // channelDataJSON is the data for a specific channel 124 type channelDataJSON struct { 125 // Key is the unique identifier for a channel in the cluster 126 Key *Key `json:"key,omitempty"` 127 128 ID string `json:"id"` // Unique id for this channel (same as for AMI) 129 Name string `json:"name"` // Name of this channel (tech/name-id format) 130 State string `json:"state"` // State of the channel 131 Accountcode string `json:"accountcode"` 132 Caller *CallerID `json:"caller"` // CallerId of the calling endpoint 133 Connected *CallerID `json:"connected"` // CallerId of the connected line 134 Creationtime DateTime `json:"creationtime"` 135 Dialplan *DialplanCEP `json:"dialplan"` // Current location in the dialplan 136 ChannelVars map[string]string `json:"channelvars"` 137 } 138 139 // MarshalJSON encodes ChannelData to JSON 140 func (d *ChannelData) MarshalJSON() ([]byte, error) { 141 t, err := ptypes.TimestampFromProto(d.Creationtime) 142 if err != nil { 143 Logger.Debug("ignoring failed creationtime timestamp parsing", "error", err) 144 } 145 146 return json.Marshal(&channelDataJSON{ 147 Key: d.Key, 148 ID: d.ID, 149 Name: d.Name, 150 State: d.State, 151 Accountcode: d.Accountcode, 152 Caller: d.Caller, 153 Connected: d.Connected, 154 Creationtime: DateTime(t), 155 Dialplan: d.Dialplan, 156 ChannelVars: d.ChannelVars, 157 }) 158 } 159 160 // UnmarshalJSON decodes ChannelData from JSON 161 func (d *ChannelData) UnmarshalJSON(data []byte) error { 162 in := new(channelDataJSON) 163 err := json.Unmarshal(data, in) 164 if err != nil { 165 return err 166 } 167 168 t, err := ptypes.TimestampProto(time.Time(in.Creationtime)) 169 if err != nil { 170 Logger.Debug("ignoring failed creationtime timestamp parsing", "error", err) 171 } 172 173 *d = ChannelData{ 174 Key: in.Key, 175 ID: in.ID, 176 Name: in.Name, 177 State: in.State, 178 Accountcode: in.Accountcode, 179 Caller: in.Caller, 180 Connected: in.Connected, 181 Creationtime: t, 182 Dialplan: in.Dialplan, 183 ChannelVars: in.ChannelVars, 184 } 185 return nil 186 } 187 188 // ChannelCreateRequest describes how a channel should be created, when 189 // using the separate Create and Dial calls. 190 type ChannelCreateRequest struct { 191 // Endpoint is the target endpoint for the dial 192 Endpoint string `json:"endpoint"` 193 194 // App is the name of the Stasis application to execute on connection 195 App string `json:"app"` 196 197 // AppArgs is the set of (comma-separated) arguments for the Stasis App 198 AppArgs string `json:"appArgs,omitempty"` 199 200 // ChannelID is the ID to give to the newly-created channel 201 ChannelID string `json:"channelId,omitempty"` 202 203 // OtherChannelID is the ID of the second created channel (when creating Local channels) 204 OtherChannelID string `json:"otherChannelId,omitempty"` 205 206 // Originator is the unique ID of the calling channel, for which this new channel-dial is being created 207 Originator string `json:"originator,omitempty"` 208 209 // Formats is the comma-separated list of valid codecs to allow for the new channel, in the case that 210 // the Originator is not specified 211 Formats string `json:"formats,omitempty"` 212 } 213 214 // SnoopOptions enumerates the non-required arguments for the snoop operation 215 type SnoopOptions struct { 216 // App is the ARI application into which the newly-created Snoop channel should be dropped. 217 App string `json:"app"` 218 219 // AppArgs is the set of arguments to pass with the newly-created Snoop channel's entry into ARI. 220 AppArgs string `json:"appArgs,omitempty"` 221 222 // Spy describes the direction of audio on which to spy (none, in, out, both). 223 // The default is 'none'. 224 Spy Direction `json:"spy,omitempty"` 225 226 // Whisper describes the direction of audio on which to send (none, in, out, both). 227 // The default is 'none'. 228 Whisper Direction `json:"whisper,omitempty"` 229 } 230 231 // ChannelHandle provides a wrapper on the Channel interface for operations on a particular channel ID. 232 type ChannelHandle struct { 233 key *Key 234 c Channel 235 236 exec func(ch *ChannelHandle) error 237 238 executed bool 239 } 240 241 // NewChannelHandle returns a handle to the given ARI channel 242 func NewChannelHandle(key *Key, c Channel, exec func(ch *ChannelHandle) error) *ChannelHandle { 243 return &ChannelHandle{ 244 key: key, 245 c: c, 246 exec: exec, 247 } 248 } 249 250 // ID returns the identifier for the channel handle 251 func (ch *ChannelHandle) ID() string { 252 return ch.key.ID 253 } 254 255 // Key returns the key for the channel handle 256 func (ch *ChannelHandle) Key() *Key { 257 return ch.key 258 } 259 260 // Exec executes any staged channel operations attached to this handle. 261 func (ch *ChannelHandle) Exec() (err error) { 262 if !ch.executed { 263 ch.executed = true 264 if ch.exec != nil { 265 err = ch.exec(ch) 266 ch.exec = nil 267 } 268 } 269 return err 270 } 271 272 // Data returns the channel's data 273 func (ch *ChannelHandle) Data() (*ChannelData, error) { 274 return ch.c.Data(ch.key) 275 } 276 277 // Continue tells Asterisk to return the channel to the dialplan 278 func (ch *ChannelHandle) Continue(context, extension string, priority int) error { 279 return ch.c.Continue(ch.key, context, extension, priority) 280 } 281 282 //--- 283 // Play/Record operations 284 //--- 285 286 // Play initiates playback of the specified media uri 287 // to the channel, returning the Playback handle 288 func (ch *ChannelHandle) Play(id string, mediaURI string) (ph *PlaybackHandle, err error) { 289 return ch.c.Play(ch.key, id, mediaURI) 290 } 291 292 // Record records the channel to the given filename 293 func (ch *ChannelHandle) Record(name string, opts *RecordingOptions) (*LiveRecordingHandle, error) { 294 return ch.c.Record(ch.key, name, opts) 295 } 296 297 // StagePlay stages a `Play` operation. 298 func (ch *ChannelHandle) StagePlay(id string, mediaURI string) (*PlaybackHandle, error) { 299 return ch.c.StagePlay(ch.key, id, mediaURI) 300 } 301 302 // StageRecord stages a `Record` operation 303 func (ch *ChannelHandle) StageRecord(name string, opts *RecordingOptions) (*LiveRecordingHandle, error) { 304 return ch.c.StageRecord(ch.key, name, opts) 305 } 306 307 //--- 308 // Hangup Operations 309 //--- 310 311 // Busy hangs up the channel with the "busy" cause code 312 func (ch *ChannelHandle) Busy() error { 313 return ch.c.Busy(ch.key) 314 } 315 316 // Congestion hangs up the channel with the congestion cause code 317 func (ch *ChannelHandle) Congestion() error { 318 return ch.c.Congestion(ch.key) 319 } 320 321 // Hangup hangs up the channel with the normal cause code 322 func (ch *ChannelHandle) Hangup() error { 323 return ch.c.Hangup(ch.key, "normal") 324 } 325 326 //-- 327 328 // -- 329 // Answer operations 330 // -- 331 332 // Answer answers the channel 333 func (ch *ChannelHandle) Answer() error { 334 return ch.c.Answer(ch.key) 335 } 336 337 // IsAnswered checks the current state of the channel to see if it is "Up" 338 func (ch *ChannelHandle) IsAnswered() (bool, error) { 339 updated, err := ch.Data() 340 if err != nil { 341 return false, errors.Wrap(err, "Failed to get updated channel") 342 } 343 return strings.ToLower(updated.State) == "up", nil 344 } 345 346 // ------ 347 348 // -- 349 // Ring Operations 350 // -- 351 352 // Ring indicates ringing to the channel 353 func (ch *ChannelHandle) Ring() error { 354 return ch.c.Ring(ch.key) 355 } 356 357 // StopRing stops ringing on the channel 358 func (ch *ChannelHandle) StopRing() error { 359 return ch.c.StopRing(ch.key) 360 } 361 362 // ------ 363 364 // -- 365 // Mute operations 366 // -- 367 368 // Mute mutes the channel in the given direction (in, out, both) 369 func (ch *ChannelHandle) Mute(dir Direction) (err error) { 370 if dir == "" { 371 dir = DirectionIn 372 } 373 374 return ch.c.Mute(ch.key, dir) 375 } 376 377 // Unmute unmutes the channel in the given direction (in, out, both) 378 func (ch *ChannelHandle) Unmute(dir Direction) (err error) { 379 if dir == "" { 380 dir = DirectionIn 381 } 382 383 return ch.c.Unmute(ch.key, dir) 384 } 385 386 // ---- 387 388 // -- 389 // Hold operations 390 // -- 391 392 // Hold puts the channel on hold 393 func (ch *ChannelHandle) Hold() error { 394 return ch.c.Hold(ch.key) 395 } 396 397 // StopHold retrieves the channel from hold 398 func (ch *ChannelHandle) StopHold() error { 399 return ch.c.StopHold(ch.key) 400 } 401 402 // ---- 403 404 // -- 405 // Music on hold operations 406 // -- 407 408 // MOH plays music on hold of the given class 409 // to the channel 410 func (ch *ChannelHandle) MOH(mohClass string) error { 411 return ch.c.MOH(ch.key, mohClass) 412 } 413 414 // StopMOH stops playing of music on hold to the channel 415 func (ch *ChannelHandle) StopMOH() error { 416 return ch.c.StopMOH(ch.key) 417 } 418 419 // ---- 420 421 // GetVariable returns the value of a channel variable 422 func (ch *ChannelHandle) GetVariable(name string) (string, error) { 423 return ch.c.GetVariable(ch.key, name) 424 } 425 426 // SetVariable sets the value of a channel variable 427 func (ch *ChannelHandle) SetVariable(name, value string) error { 428 return ch.c.SetVariable(ch.key, name, value) 429 } 430 431 // -- 432 // Misc 433 // -- 434 435 // Originate creates (and dials) a new channel using the present channel as its Originator. 436 func (ch *ChannelHandle) Originate(req OriginateRequest) (*ChannelHandle, error) { 437 if req.Originator == "" { 438 req.Originator = ch.ID() 439 } 440 return ch.c.Originate(ch.key, req) 441 } 442 443 // StageOriginate stages an originate (channel creation and dial) to be Executed later. 444 func (ch *ChannelHandle) StageOriginate(req OriginateRequest) (*ChannelHandle, error) { 445 if req.Originator == "" { 446 req.Originator = ch.ID() 447 } 448 449 return ch.c.StageOriginate(ch.key, req) 450 } 451 452 // Create creates (but does not dial) a new channel, using the present channel as its Originator. 453 func (ch *ChannelHandle) Create(req ChannelCreateRequest) (*ChannelHandle, error) { 454 if req.Originator == "" { 455 req.Originator = ch.ID() 456 } 457 458 return ch.c.Create(ch.key, req) 459 } 460 461 // Dial dials a created channel. `caller` is the optional 462 // channel ID of the calling party (if there is one). Timeout 463 // is the length of time to wait before the dial is answered 464 // before aborting. 465 func (ch *ChannelHandle) Dial(caller string, timeout time.Duration) error { 466 return ch.c.Dial(ch.key, caller, timeout) 467 } 468 469 // Snoop spies on a specific channel, creating a new snooping channel placed into the given app 470 func (ch *ChannelHandle) Snoop(snoopID string, opts *SnoopOptions) (*ChannelHandle, error) { 471 return ch.c.Snoop(ch.key, snoopID, opts) 472 } 473 474 // StageSnoop stages a `Snoop` operation 475 func (ch *ChannelHandle) StageSnoop(snoopID string, opts *SnoopOptions) (*ChannelHandle, error) { 476 return ch.c.StageSnoop(ch.key, snoopID, opts) 477 } 478 479 // ---- 480 481 // -- 482 // Silence operations 483 // -- 484 485 // Silence plays silence to the channel 486 func (ch *ChannelHandle) Silence() error { 487 return ch.c.Silence(ch.key) 488 } 489 490 // StopSilence stops silence to the channel 491 func (ch *ChannelHandle) StopSilence() error { 492 return ch.c.StopSilence(ch.key) 493 } 494 495 // ---- 496 497 // -- 498 // Subscription 499 // -- 500 501 // Subscribe subscribes the list of channel events 502 func (ch *ChannelHandle) Subscribe(n ...string) Subscription { 503 if ch == nil { 504 return nil 505 } 506 return ch.c.Subscribe(ch.key, n...) 507 } 508 509 // TODO: rest of ChannelHandle 510 511 // -- 512 // DTMF 513 // -- 514 515 // SendDTMF sends the DTMF information to the server 516 func (ch *ChannelHandle) SendDTMF(dtmf string, opts *DTMFOptions) error { 517 return ch.c.SendDTMF(ch.key, dtmf, opts) 518 }