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  }