Categorygithub.com/mtryfoss/ari
modulepackage
4.8.4+incompatible
Repository: https://github.com/mtryfoss/ari.git
Documentation: pkg.go.dev

# README

ari - Golang Asterisk Rest Interface (ARI) library

Build Status

This library allows you to easily access ARI in go applications. The Asterisk Rest Interface (https://wiki.asterisk.org/wiki/pages/viewpage.action?pageId=29395573) is an asynchronous API which allows you to access basic Asterisk objects for custom communications applications.

This project also includes some convenience wrappers for various tasks, found in /ext. These include go-idiomatic utilities for playing audio, IVRs, recordings, and other tasks which are tricky to coordinate nicely in ARI alone.

Getting started

This library maintains semver, and APIs between major releases do change. Therefore, always use a vendoring tool which supports semver, such as dep.

Version 4.x.x is the current version. It offers a number of new features focused on facilitating ARI across large clusters and simplifies the API.

There is also a NATS-based ari-proxy which is designed to work with this client library. It can be found at CyCoreSystems/ari-proxy.

Install with:

go get github.com/CyCoreSystems/ari

Features

Cloud-ready

All configuration options for the client can be sourced by environment variable, making it easy to build applications without configuration files. The default connection to Asterisk is set to localhost on port 8088, which should run on Kubernetes deployments without configuration.

The available environment variables (and defaults) are:

  • ARI_APPLICATION (randomly-generated ID)
  • ARI_URL (http://localhost:8088/ari)
  • ARI_WSURL (ws://localhost:8088/ari/events)
  • ARI_WSORIGIN (http://localhost/)
  • ARI_USERNAME (none)
  • ARI_PASSWORD (none)

If using ari-proxy, the process is even easier.

Resource Keys

In order to facilitate the construction of ARI systems across many Asterisk instances, in version 4, we introduce the concept of Resource Keys. Previous versions expected a simple ID (string) field for the identification of a resource to ARI. This reflects how ARI itself operates. However, for systems with multiple Asterisk instances, more metadata is necessary in order to properly address a resource. Specifically, we need to know the Asterisk node. There is also the concept of a Dialog, which offers an orthogonal logical grouping of events which transcends nodes and applications. This is not meaningful in the native client, but other transports, such as the ARI proxy, may make use of this for alternative routing of events. This Key includes all of these data.

package ari

// Key identifies a unique resource in the system
type Key struct {
   // Kind indicates the type of resource the Key points to.  e.g., "channel",
   // "bridge", etc.
   Kind string   `json:"kind"`

   // ID indicates the unique identifier of the resource
   ID string `json:"id"`

   // Node indicates the unique identifier of the Asterisk node on which the
   // resource exists or will be created
   Node string `json:"node,omitempty"`

   // Dialog indicates a named scope of the resource, for receiving events
   Dialog string `json:"dialog,omitempty"`
}

At a basic level, when the specific Asterisk ID is not needed, a key can consist of a simple ID string:

  key := ari.NewKey(ari.ChannelKey, "myID")

For more interesting systems, however, we can declare the Node ID:

  key := ari.NewKey(ari.BridgeKey, "myID", ari.WithNode("00:01:02:30:40:50"))

We can also bind a dialog:

  key := ari.NewKey(ari.ChannelKey, "myID",
   ari.WithNode("00:01:02:30:40:50"),
   ari.WithDialog("privateConversation"))

We can also create a new key from an existing key. This allows us to easily copy the location information from the original key to a new key of a different resource. The location information is everything (including the Dialog) except for the key Kind and ID.

  brKey := key.New(ari.BridgeKey, "myBridgeID")

All ARI operations which accepted an ID for an operator now expect an *ari.Key instead. In many cases, this can be easily back-ported by wrapping IDs with ari.NewKey("channel", id).

Handles

Handles for all of the major entity types are available, which bundle in the tracking of resources with their manipulations. Every handle, at a minimum, internally tracks the resource's cluster-unique Key and the ARI client connection through which the entity is being interacted. Using a handle generally results in less and more readable code.

For instance, instead of calling:

ariClient.Channel().Hangup(channelKey, "normal")

you could just call Hangup() on the handle:

h.Hangup()

While the lower level direct calls have maintained fairly strict semantics to match the formal ARI APIs, the handles frequently provide higher-level, simpler operations. Moreover, most of the extensions (see below) make use of handles.

In general, when operating on longer lifetime entities (such as channels and bridges), it is easier to use handles wherever you can rather than tracking Keys and clients discretely.

Obtaining a Handle from a Key is very simple; just call the Get() operation on the resource interface appropriate to the key. The Get() operation is a local-only operation which does not interact with the Asterisk or ARI proxy at all, and it is thus quite efficient.

h := ariClient.Channel().Get(channelKey)

Staging resources

A common issue for ARI resources is making sure a subscription exists before events for that resource are sent. Otherwise, important events which occur too quickly can become lost. This results in a chicken-and-egg problem for subscriptions.

In order to address this common issue, resource handles creation operations now offer a StageXXXX variant, which returns the handle for the resource without actually creating the resource. Once all of the subscriptions are bound to this handle, the caller may call resource.Exec() in order to create the resource in Asterisk.

   h := NewChannelHandle(key, c, nil)

   // Stage a playback
   pb, err := h.StagePlay("myPlaybackID", "sound:tt-monkeys")
   if err != nil {
      return err
   }
   
   // Add a subscription to the staged playback
   startSub := pb.Subscribe(EventTypes.PlaybackStarted)
   defer startSub.Cancel()

   // Execute the staged playback
   pb.Exec()

   // Wait for something to happen
   select {
      case <-time.After(time.Second):
        fmt.Println("timeout waiting for playback to start")
        return errors.New("timeout")
      case <-startSub.Events():
        fmt.Println("playback started")
   }

Extensions

There are a number of extensions which wrap the lower-level operations in higher-level ones, making it easier to perform many common tasks.

AudioURI

Constructing Asterisk audio playback URIs can be a bit tedious, particularly for handling certain edge cases in digits and for constructing dates.

The audiouri package provides a number of routines to make the construction of these URIs simpler.

Bridgemon

Monitoring a bridge for events and data updates is not difficult, but it involves a lot of code and often makes several wasteful calls to obtain bridge data, particularly when accessing it on large bridges.

Bridgemon provides a cache and proxy for the bridge data and bridge events so that a user can simply Watch() for changes in the bridge state and efficiently retrieve the updated data without multiple requests.

It also shuts itself down automatically when the bridge it is monitoring is destroyed.

Play

Playback of media and waiting for (DTMF) responses therefrom is an incredibly common task in telephony. ARI provides many tools to perform these types of actions, but the asynchronous nature of the interface makes it fairly tedious to build these kinds of things.

In ext/play, there resides a tool for executing many common tasks surrounding media playback and response sequences. The core function, play.Play() plays, in sequence, a series of audio media URIs. It can be extended to expect and (optionally) wait for a DTMF response by supplying it with a Match function. There is a small convenience wrapper play.Prompt() which sets some common defaults for playbacks which expect a response.

The execution of a Play is configured by any number of option functions, which supply structured modifiers for the behaviour of the playback. You can even supply your own Match function for highly-customized matching.

Record

Making recordings is another complicated but common task for ARI applications. The ext/record, we provide a simple wrapper which facilitates many common recording-related operations inside a single recording Session wrapper.

Features include:

  • record with or without a beep at the start
  • listen for various termination types: hangup, dtmf, silence, timeout
  • review, scrap, and save recordings upon completion
  • retrieve the playback URI for the recording

Documentation and Examples

Go documentation is available at https://godoc.org/github.com/CyCoreSystems/ari

Examples for helloworld, play, script, bridge, and record are available. Set your environment variables as described above (at minimum, ARI_USERNAME and ARI_PASSWORD) and run:

cd /_examples/helloworld
go run ./main.go

Other examples:

  • stasisStart demonstrates a simple click-to-call announcer system
  • stasisStart-nats demonstrates the same click-to-call using the NATS-based ARI proxy
  • bridge demonstrates a simple conference bridge
  • play demonstrates the use of the ext/play extension
  • record demonstrates the use of the ext/record extension

The files in _ext/infra demonstrates the minimum necessary changes to the Asterisk configuration to enable the operation of ARI.

Tests

Run go test to verify

Contributing

Contributions welcomed. Changes with tests and descriptive commit messages will get priority handling.

License

Licensed under the Apache License, Version 2.0

# Packages

No description provided by the author
No description provided by the author
Package rid provides unique resource IDs.
No description provided by the author

# Functions

AppKey returns a key that is bound to the given application.
CallerIDFromString interprets the provided string as a CallerID.
ChannelContext returns a context which is closed when the provided channel leaves the ARI application or the parent context is closed.
ConfigID returns the configuration Key ID for the given configuration class, type/kind, and id.
DecodeEvent converts a JSON-encoded event to an ARI event.
DialogKey returns a key that is bound to the given dialog.
EndpointID returns the endpoint Key ID for the given tech and resource.
FromEndpointID converts the endpoint ID to the tech, resource pair.
HangupOnEnd indicates that the channel should be terminated when the channel context is terminated.
KindKey returns a key that is bound by a type only.
NewApplicationHandle creates a new handle to the application name.
NewBridgeHandle creates a new bridge handle.
NewChannelHandle returns a handle to the given ARI channel.
NewConfigHandle builds a new config handle.
NewDeviceStateHandle creates a new deviceState handle.
NewEndpointHandle creates a new EndpointHandle.
NewEndpointKey returns the key for the given endpoint.
NewKey builds a new key given the kind, identifier, and any optional arguments.
NewLiveRecordingHandle creates a new live recording handle.
NewLogHandle builds a new log handle given the `Key` and `Logging`` client.
NewMailboxHandle creates a new mailbox handle given the name and mailbox transport.
NewModuleHandle returns a new module handle.
NewNullSubscription returns a subscription which never returns any events.
NewPlaybackHandle builds a handle to the playback id.
NewStoredRecordingHandle creates a new stored recording handle.
NodeKey returns a key that is bound to the given application and node.
Once listens for the first event of the provided types, returning a channel which supplies that event.
ParseConfigID parses the provided Config ID into its Class, Type, and ID components.
WithApp sets the given node identifier on the key.
WithDialog sets the given dialog identifier on the key.
WithLocationOf copies the partial key fields Node, Application, Dialog from the reference key.
WithNode sets the given node identifier on the key.
WithParentContext requests that the generated channel context be created from the given parent context.

# Constants

ApplicationKey is the key kind for ARI Application resources.
BridgeKey is the key kind for the ARI Bridge resources.
ChannelKey is the key kind for the ARI Channel resource.
DateFormat is the date format that ARI returns in the JSON bodies.
DeviceStateKey is the key kind for the ARI DeviceState resource.
DirectionBoth indicates both the directions flowing both inward to Asterisk and outward from Asterisk.
DirectionIn indicates the direction flowing from the channel into Asterisk.
DirectionNone indicates audio should not flow in any direction.
DirectionOut indicates the direction flowing from Asterisk to the channel.
TODO: confirm separator isn't terrible.
EndpointKey is the key kind for the ARI Endpoint resource.
LiveRecordingKey is the key kind for the ARI LiveRecording resource.
LoggingKey is the key kind for the ARI Logging resource.
MailboxKey is the key kind for the ARI Mailbox resource.
ModuleKey is the key kind for the ARI Module resource.
PlaybackKey is the key kind for the ARI Playback resource.
SoundKey is the key kind for the ARI Sound resource.
StoredRecordingKey is the key kind for the ARI StoredRecording resource.
VariableKey is the key kind for the ARI Asterisk Variable resource.

# Variables

No description provided by the author
No description provided by the author
Events is the instance for grabbing event types.
Logger defaults to a discard handler (null output).

# Structs

ApplicationData describes the data for a Stasis (Ari) application.
ApplicationHandle provides a wrapper to an Application interface for operations on a specific application.
ApplicationReplaced - "Notification that another WebSocket has taken over for an application.An application may only be subscribed to by a single WebSocket at a time.
AsteriskInfo describes a running asterisk system.
BridgeAttendedTransfer - "Notification that an attended transfer has occurred.".
BridgeBlindTransfer - "Notification that a blind transfer has occurred.".
BridgeCreated - "Notification that a bridge has been created.".
BridgeData describes an Asterisk Bridge, the entity which merges media from one or more channels into a common audio output.
BridgeDestroyed - "Notification that a bridge has been destroyed.".
BridgeHandle is the handle to a bridge for performing operations.
BridgeMerged - "Notification that one bridge has merged into another.".
BridgeVideoSourceChanged - "Notification that the source of video in a bridge has changed.".
BuildInfo describes information about how Asterisk was built.
CallerID describes the name and number which identifies the caller to other endpoints.
ChannelCallerID - "Channel changed Caller ID.".
ChannelConnectedLine - "Channel changed Connected Line.".
ChannelContextOptions describes the set of options to be used when creating a channel-bound context.
ChannelCreated - "Notification that a channel has been created.".
ChannelCreateRequest describes how a channel should be created, when using the separate Create and Dial calls.
ChannelData describes the data for a specific channel.
ChannelDestroyed - "Notification that a channel has been destroyed.".
ChannelDialplan - "Channel changed location in the dialplan.".
ChannelDtmfReceived - "DTMF received on a channel.This event is sent when the DTMF ends.
ChannelEnteredBridge - "Notification that a channel has entered a bridge.".
ChannelHandle provides a wrapper on the Channel interface for operations on a particular channel ID.
ChannelHangupRequest - "A hangup was requested on the channel.".
ChannelHold - "A channel initiated a media hold.".
ChannelLeftBridge - "Notification that a channel has left a bridge.".
ChannelStateChange - "Notification of a channel's state change.".
ChannelTalkingFinished - "Talking is no longer detected on the channel.".
ChannelTalkingStarted - "Talking was detected on the channel.".
ChannelUnhold - "A channel initiated a media unhold.".
ChannelUserevent - "User-generated event with additional user-defined fields in the object.".
ChannelVarset - "Channel variable changed.".
ConfigData contains the data for a given configuration object.
A ConfigHandle is a reference to a Config object on the asterisk service.
ConfigInfo describes information about the Asterisk configuration.
ConfigTuple is the key-value pair that defines a configuration entry.
ConfigTupleList wrap a list for asterisk ari require.
ContactInfo - "Detailed information about a contact on an endpoint.".
ContactStatusChange - "The state of a contact on an endpoint has changed.".
DeviceStateChanged - "Notification that a device state has changed.".
DeviceStateData is the device state for the device.
DeviceStateHandle is a representation of a device state that can be interacted with.
Dial - "Dialing state has changed.".
Dialplan describes a location in the Asterisk dialplan.
DTMFOptions is the list of pptions for DTMF sending.
EndpointData describes an external device which may offer or accept calls to or from Asterisk.
An EndpointHandle is a reference to an endpoint attached to a transport to an asterisk server.
EndpointStateChange - "Endpoint state changed.".
EventData provides the basic metadata for an ARI event.
EventTypes enumerates the list of event types.
FormatLangPair describes the format and language of a sound file.
Key identifies a unique resource in the system.
LiveRecordingData is the data for a live recording.
A LiveRecordingHandle is a reference to a live recording that can be operated on.
LogData represents the log data.
LogHandle provides an interface to manipulate a logging channel.
MailboxData respresents the state of an Asterisk (voice) mailbox.
A MailboxHandle is a handle to a mailbox instance attached to an ari transport.
Message is the first extension of the RawMessage type, containing only a Type.
MissingParams - "Error event sent when required params are missing.".
ModuleData is the data for an asterisk module.
ModuleHandle is the reference to an asterisk module.
NullSubscription is a subscription which never returns any events.
OriginateRequest defines the parameters for the creation of a new Asterisk channel.
Peer - "Detailed information about a remote peer that communicates with Asterisk.".
PeerStatusChange - "The state of a peer associated with an endpoint has changed.".
PlaybackContinuing - "Event showing the continuation of a media playback operation from one media URI to the next in the list.".
PlaybackData represents the state of a playback.
PlaybackFinished - "Event showing the completion of a media playback operation.".
PlaybackHandle is the handle for performing playback operations.
PlaybackStarted - "Event showing the start of a media playback operation.".
Recording is a namespace for the recording types.
RecordingFailed - "Event showing failure of a recording operation.".
RecordingFinished - "Event showing the completion of a recording operation.".
RecordingOptions describes the set of options available when making a recording.
RecordingStarted - "Event showing the start of a recording operation.".
SetID describes a userid/groupid pair.
SnoopOptions enumerates the non-required arguments for the snoop operation.
SoundData describes a media file which may be played back.
StasisEnd - "Notification that a channel has left a Stasis application.".
StasisStart - "Notification that a channel has entered a Stasis application.".
StatusInfo describes the state of an Asterisk system.
StoredRecordingData is the data for a stored recording.
A StoredRecordingHandle is a reference to a stored recording that can be operated on.
SystemInfo describes information about the Asterisk system.
TextMessageData describes text message.
TextMessageReceived - "A text message was received from an endpoint.".
TextMessageVariable describes a key-value pair (associated with a text message).

# Interfaces

Application represents a communication path interacting with an Asterisk server for application-level resources.
Asterisk represents a communication path for the Asterisk server for system-level resources.
AsteriskVariables is an interface to interact with Asterisk global variables.
Bridge represents a communication path to an Asterisk server for working with bridge resources.
Bus is an event bus for ARI events.
Channel represents a communication path interacting with an Asterisk server.
Client represents a set of operations to interact with an Asterisk ARI server.
Config represents a transport to the asterisk config ARI resource.
DeviceState represents a communication path interacting with an Asterisk server for device state resources.
DTMFSender is an object which can be send DTMF signals.
Endpoint represents a communication path to an Asterisk server for endpoint resources.
Event is the top level event interface.
LiveRecording represents a communication path interacting with an Asterisk server for live recording resources.
Logging represents a communication path to an Asterisk server for working with logging resources.
Mailbox is the communication path to an Asterisk server for operating on mailbox resources.
A Matcher provides the functionality for matching against a key.
Modules is the communication path for interacting with the asterisk modules resource.
Playback represents a communication path for interacting with an Asterisk server for playback resources.
A Player is an entity which can play an audio URI.
Recorder describes an interface of something which can Record.
A Sender is an entity which can send event bus messages.
Sound represents a communication path to the asterisk server for Sound resources.
StoredRecording represents a communication path interacting with an Asterisk server for stored recording resources.
A Subscriber is an entity which can create ARI event subscriptions.
A Subscription is a subscription on series of ARI events.
TextMessage needs some verbiage here.

# Type aliases

ChannelContextOptionFunc describes a function which modifies channel context options.
DateTime is an alias type for attaching a custom asterisk unmarshaller and marshaller for JSON.
Direction describes an audio direction, as used by Mute, Snoop, and possibly others.
DurationSec is a JSON type for duration in seconds.
Header represents a set of key-value pairs to store transport-related metadata on Events.
KeyOptionFunc is a functional argument alias for providing options for ARI keys.
Keys is a list of keys.
MatchFunc is the functional type alias for providing functional `Matcher` implementations.