diff --git a/client/channel.go b/client/channel.go index 2ec34f3..aabed2a 100644 --- a/client/channel.go +++ b/client/channel.go @@ -50,6 +50,9 @@ func (c *channel) StageOriginate(referenceKey *ari.Key, o ari.OriginateRequest) o.ChannelID = rid.New(rid.Channel) } + // We go ahead an call the createRequest on the server so that we lock in an + // Asterisk box at the time of staging even though this staging call will + // never actually be used. k, err := c.c.createRequest(&proxy.Request{ Kind: "ChannelStageOriginate", Key: referenceKey, @@ -243,6 +246,8 @@ func (c *channel) Snoop(key *ari.Key, snoopID string, opts *ari.SnoopOptions) (* } func (c *channel) StageSnoop(key *ari.Key, snoopID string, opts *ari.SnoopOptions) (*ari.ChannelHandle, error) { + // this getRequest is done merely to locate the Asterisk box on which the + // snoop will be initiated. It will never actually be Exec'd k, err := c.c.getRequest(&proxy.Request{ Kind: "ChannelStageSnoop", Key: key, @@ -260,6 +265,47 @@ func (c *channel) StageSnoop(key *ari.Key, snoopID string, opts *ari.SnoopOption }), nil } +func (c *channel) ExternalMedia(referenceKey *ari.Key, opts ari.ExternalMediaOptions) (*ari.ChannelHandle, error) { + if opts.ChannelID == "" { + opts.ChannelID = rid.New(rid.Channel) + } + k, err := c.c.createRequest(&proxy.Request{ + Kind: "ChannelExternalMedia", + Key: referenceKey, + ChannelExternalMedia: &proxy.ChannelExternalMedia{ + Options: opts, + }, + }) + if err != nil { + return nil, err + } + return ari.NewChannelHandle(k, c, nil), nil +} + +func (c *channel) StageExternalMedia(referenceKey *ari.Key, opts ari.ExternalMediaOptions) (*ari.ChannelHandle, error) { + if opts.ChannelID == "" { + opts.ChannelID = rid.New(rid.Channel) + } + + // We go ahead an call the createRequest on the server so that we lock in an + // Asterisk box at the time of staging even though this staging call will + // never actually be used. + k, err := c.c.createRequest(&proxy.Request{ + Kind: "ChannelStageOriginate", + Key: referenceKey, + ChannelExternalMedia: &proxy.ChannelExternalMedia{ + Options: opts, + }, + }) + if err != nil { + return nil, err + } + return ari.NewChannelHandle(k, c, func(h *ari.ChannelHandle) error { + _, err := c.ExternalMedia(k, opts) + return err + }), nil +} + func (c *channel) Dial(key *ari.Key, caller string, timeout time.Duration) error { return c.c.commandRequest(&proxy.Request{ Kind: "ChannelDial", diff --git a/go.mod b/go.mod index 659d75d..3b70f2e 100644 --- a/go.mod +++ b/go.mod @@ -4,26 +4,22 @@ go 1.12 require ( github.com/BurntSushi/toml v0.3.1 // indirect - github.com/CyCoreSystems/ari v5.0.0-pre5+incompatible + github.com/CyCoreSystems/ari v5.0.0-pre7+incompatible github.com/fsnotify/fsnotify v0.0.0-20170329110642-4da3e2cfbabc // indirect github.com/hashicorp/hcl v0.0.0-20170509225359-392dba7d905e // indirect github.com/inconshreveable/log15 v0.0.0-20171019012758-0decfc6c20d9 github.com/inconshreveable/mousetrap v1.0.0 // indirect - github.com/kr/pretty v0.1.0 // indirect github.com/magiconair/properties v1.7.3 // indirect github.com/mitchellh/mapstructure v0.0.0-20170523030023-d0303fe80992 // indirect github.com/nats-io/nats-server/v2 v2.0.0 // indirect github.com/nats-io/nats.go v1.8.1 github.com/pelletier/go-toml v0.0.0-20170817000623-4692b8f9babf // indirect - github.com/pkg/errors v0.8.0 + github.com/pkg/errors v0.8.1 github.com/spf13/afero v0.0.0-20170217164146-9be650865eab // indirect github.com/spf13/cast v1.1.0 // indirect github.com/spf13/cobra v0.0.2 github.com/spf13/jwalterweatherman v0.0.0-20170523133247-0efa5202c046 // indirect github.com/spf13/pflag v1.0.0 // indirect github.com/spf13/viper v1.0.2 - github.com/stretchr/testify v1.3.0 - golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5 // indirect - gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect - gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7 // indirect + github.com/stretchr/testify v1.4.0 ) diff --git a/go.sum b/go.sum index 10bc88e..f3eb84e 100644 --- a/go.sum +++ b/go.sum @@ -2,6 +2,8 @@ github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/CyCoreSystems/ari v5.0.0-pre5+incompatible h1:41WZopBWACn3uhcGaau3oEFRW2KX+LdOo1CNMJENN2s= github.com/CyCoreSystems/ari v5.0.0-pre5+incompatible/go.mod h1:EjkV7D03yBCsTWgwDjGlPPktsPdjWIdEZ8RnZJwloXA= +github.com/CyCoreSystems/ari v5.0.0-pre7+incompatible h1:OC3g9wcNeKYv7itwuBwIZvmIeCbf7C08Llwmq+xSxiI= +github.com/CyCoreSystems/ari v5.0.0-pre7+incompatible/go.mod h1:qXO2XTsScgwHY6+LbahBCuh61zdT5vTrCAbGlYz85VU= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -9,8 +11,12 @@ github.com/fsnotify/fsnotify v0.0.0-20170329110642-4da3e2cfbabc h1:fqUzyjP8DApxX github.com/fsnotify/fsnotify v0.0.0-20170329110642-4da3e2cfbabc/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/go-stack/stack v1.7.0 h1:S04+lLfST9FvL8dl4R31wVUC/paZp/WQZbLmUgWboGw= github.com/go-stack/stack v1.7.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gogo/protobuf v1.0.0 h1:2jyBKDKU/8v3v2xVR2PtiWQviFUyiaGk2rpfyFT8rTM= github.com/gogo/protobuf v1.0.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.3.0 h1:G8O7TerXerS4F6sx9OV7/nRfJdnXgHZu/S/7F2SN+UE= +github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/hashicorp/hcl v0.0.0-20170509225359-392dba7d905e h1:KJWs1uTCkN3E/J5ofCH9Pf8KKsibTFc3fv0CA9+WsVo= @@ -19,6 +25,8 @@ github.com/inconshreveable/log15 v0.0.0-20171019012758-0decfc6c20d9 h1:LmBUkXNSS github.com/inconshreveable/log15 v0.0.0-20171019012758-0decfc6c20d9/go.mod h1:cOaXtrgN4ScfRrD9Bre7U1thNq5RtJ8ZoP4iXVGRj6o= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -28,8 +36,13 @@ github.com/magiconair/properties v1.7.3 h1:6AOjgCKyZFMG/1yfReDPDz3CJZPxnYk7DGmj2 github.com/magiconair/properties v1.7.3/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-isatty v0.0.3 h1:ns/ykhmWi7G9O+8a448SecJU3nSMBXJfqQkl0upE1jI= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.10 h1:qxFzApOv4WsAL965uUPIsXzAKCZxN2p9UqdhFS4ZW10= +github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mitchellh/mapstructure v0.0.0-20170523030023-d0303fe80992 h1:W7VHAEVflA5/eTyRvQ53Lz5j8bhRd1myHZlI/IZFvbU= github.com/mitchellh/mapstructure v0.0.0-20170523030023-d0303fe80992/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/nats-io/jwt v0.2.6 h1:eAyoYvGgGLXR2EpnsBUvi/FcFrBqN6YKFVbOoEfPN4k= @@ -44,10 +57,14 @@ github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/oklog/ulid v0.3.0 h1:yEMMWFnYiPX/ytx1StIE0E1a35sm8MmWD/uSL9ZtKhg= github.com/oklog/ulid v0.3.0/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/pelletier/go-toml v0.0.0-20170817000623-4692b8f9babf h1:XjB5kVAWxe9qH3eZIUfsW4gLh7prYlRJmZ5zRjyvCeg= github.com/pelletier/go-toml v0.0.0-20170817000623-4692b8f9babf/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/spf13/afero v0.0.0-20170217164146-9be650865eab h1:IVAbBHQR8rXL2Fc8Zba/lMF7KOnTi70lqdx91UTuAwQ= @@ -63,25 +80,54 @@ github.com/spf13/pflag v1.0.0/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn github.com/spf13/viper v1.0.2 h1:Ncr3ZIuJn322w2k1qmzXDnkLAdQMlJqBa9kfAH+irso= github.com/spf13/viper v1.0.2/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/vektra/mockery v0.0.0-20181123154057-e78b021dcbb5/go.mod h1:ppEjwdhyy7Y31EnHRDm1JkChoC7LXIJ7Ex0VYLWtZtQ= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5 h1:58fnuSXlxZmFdJyvtTFVmVhcMLU6v5fEb/ok4wyqtNU= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190607181551-461777fb6f67 h1:rJJxsykSlULwd2P2+pg/rtnwN2FrWp4IuCxOSyS0V00= golang.org/x/net v0.0.0-20190607181551-461777fb6f67/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191027093000-83d349e8ac1a h1:Yu34BogBivvmu7SAzHHaB9nZWH5D1C+z3F1jyIaYZSQ= +golang.org/x/net v0.0.0-20191027093000-83d349e8ac1a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190608050228-5b15430b70e3 h1:xUZPeCzQtkdgRi9RjXIA+3w3RdyDLPqiaJlza5Fqpog= golang.org/x/sys v0.0.0-20190608050228-5b15430b70e3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181112210238-4b1f3b6b1646/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191026034945-b2104f82a97d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7 h1:+t9dhfO+GNOIGJof6kPOAenx7YgrZMTdRPV+EsnPabk= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/internal/integration/channel.go b/internal/integration/channel.go index 1f89124..5660dbe 100644 --- a/internal/integration/channel.go +++ b/internal/integration/channel.go @@ -6,6 +6,7 @@ import ( "time" "github.com/CyCoreSystems/ari" + "github.com/CyCoreSystems/ari/rid" tmock "github.com/stretchr/testify/mock" ) @@ -16,7 +17,6 @@ var nonEmpty = tmock.MatchedBy(func(s string) bool { return s != "" }) func TestChannelData(t *testing.T, s Server) { key := ari.NewKey(ari.ChannelKey, "c1") runTest("simple", t, s, func(t *testing.T, m *mock, cl ari.Client) { - var expected ari.ChannelData expected.ID = "c1" expected.Name = "channe1" @@ -39,8 +39,7 @@ func TestChannelData(t *testing.T, s Server) { }) runTest("error", t, s, func(t *testing.T, m *mock, cl ari.Client) { - - var expected = errors.New("Unknown error") + expected := errors.New("Unknown error") m.Channel.On("Data", key).Return(nil, expected) @@ -63,7 +62,6 @@ func TestChannelAnswer(t *testing.T, s Server) { key := ari.NewKey(ari.ChannelKey, "c1") runTest("simple", t, s, func(t *testing.T, m *mock, cl ari.Client) { - m.Channel.On("Answer", key).Return(nil) err := cl.Channel().Answer(key) @@ -77,8 +75,7 @@ func TestChannelAnswer(t *testing.T, s Server) { }) runTest("error", t, s, func(t *testing.T, m *mock, cl ari.Client) { - - var expected = errors.New("Unknown error") + expected := errors.New("Unknown error") m.Channel.On("Answer", key).Return(expected) @@ -97,7 +94,6 @@ func TestChannelBusy(t *testing.T, s Server) { key := ari.NewKey(ari.ChannelKey, "c1") runTest("simple", t, s, func(t *testing.T, m *mock, cl ari.Client) { - m.Channel.On("Busy", key).Return(nil) err := cl.Channel().Busy(key) @@ -111,8 +107,7 @@ func TestChannelBusy(t *testing.T, s Server) { }) runTest("error", t, s, func(t *testing.T, m *mock, cl ari.Client) { - - var expected = errors.New("Unknown error") + expected := errors.New("Unknown error") m.Channel.On("Busy", key).Return(expected) @@ -131,7 +126,6 @@ func TestChannelCongestion(t *testing.T, s Server) { key := ari.NewKey(ari.ChannelKey, "c1") runTest("simple", t, s, func(t *testing.T, m *mock, cl ari.Client) { - m.Channel.On("Congestion", key).Return(nil) err := cl.Channel().Congestion(key) @@ -145,8 +139,7 @@ func TestChannelCongestion(t *testing.T, s Server) { }) runTest("error", t, s, func(t *testing.T, m *mock, cl ari.Client) { - - var expected = errors.New("Unknown error") + expected := errors.New("Unknown error") m.Channel.On("Congestion", key).Return(expected) @@ -165,7 +158,6 @@ func TestChannelHangup(t *testing.T, s Server) { key := ari.NewKey(ari.ChannelKey, "c1") runTest("noReason", t, s, func(t *testing.T, m *mock, cl ari.Client) { - m.Channel.On("Hangup", key, "").Return(nil) err := cl.Channel().Hangup(key, "") @@ -179,7 +171,6 @@ func TestChannelHangup(t *testing.T, s Server) { }) runTest("aReason", t, s, func(t *testing.T, m *mock, cl ari.Client) { - m.Channel.On("Hangup", key, "busy").Return(nil) err := cl.Channel().Hangup(key, "busy") @@ -193,8 +184,7 @@ func TestChannelHangup(t *testing.T, s Server) { }) runTest("error", t, s, func(t *testing.T, m *mock, cl ari.Client) { - - var expected = errors.New("Unknown error") + expected := errors.New("Unknown error") m.Channel.On("Hangup", key, "busy").Return(expected) @@ -210,7 +200,6 @@ func TestChannelHangup(t *testing.T, s Server) { } func TestChannelList(t *testing.T, s Server) { - runTest("empty", t, s, func(t *testing.T, m *mock, cl ari.Client) { m.Channel.On("List", (*ari.Key)(nil)).Return([]*ari.Key{}, nil) @@ -228,9 +217,8 @@ func TestChannelList(t *testing.T, s Server) { }) runTest("nonEmpty", t, s, func(t *testing.T, m *mock, cl ari.Client) { - - var h1 = ari.NewKey(ari.ChannelKey, "h1") - var h2 = ari.NewKey(ari.ChannelKey, "h2") + h1 := ari.NewKey(ari.ChannelKey, "h1") + h2 := ari.NewKey(ari.ChannelKey, "h2") m.Channel.On("List", (*ari.Key)(nil)).Return([]*ari.Key{h1, h2}, nil) @@ -404,7 +392,6 @@ func TestChannelMOH(t *testing.T, s Server) { m.Channel.AssertCalled(t, "MOH", key, "music") }) - } func TestChannelStopMOH(t *testing.T, s Server) { @@ -435,19 +422,16 @@ func TestChannelStopMOH(t *testing.T, s Server) { m.Channel.AssertCalled(t, "StopMOH", key) }) - } func TestChannelCreate(t *testing.T, s Server) { - runTest("ok", t, s, func(t *testing.T, m *mock, cl ari.Client) { - req := ari.ChannelCreateRequest{} req.App = "App" req.ChannelID = "1234" chkey := ari.NewKey(ari.ChannelKey, "ch2") - var expected = ari.NewChannelHandle(chkey, m.Channel, nil) + expected := ari.NewChannelHandle(chkey, m.Channel, nil) m.Channel.On("Create", &ari.Key{Kind: "", ID: "", Node: "", Dialog: "", App: ""}, req).Return(expected, nil) @@ -467,7 +451,6 @@ func TestChannelCreate(t *testing.T, s Server) { }) runTest("err", t, s, func(t *testing.T, m *mock, cl ari.Client) { - req := ari.ChannelCreateRequest{} req.App = "App" req.ChannelID = "1234" @@ -492,7 +475,6 @@ func TestChannelContinue(t *testing.T, s Server) { key := ari.NewKey(ari.ChannelKey, "c1") runTest("ok", t, s, func(t *testing.T, m *mock, cl ari.Client) { - m.Channel.On("Continue", key, "ctx1", "ext1", 0).Return(nil) err := cl.Channel().Continue(key, "ctx1", "ext1", 0) @@ -506,7 +488,6 @@ func TestChannelContinue(t *testing.T, s Server) { }) runTest("err", t, s, func(t *testing.T, m *mock, cl ari.Client) { - m.Channel.On("Continue", key, "ctx1", "ext1", 0).Return(errors.New("error")) err := cl.Channel().Continue(key, "ctx1", "ext1", 0) @@ -524,7 +505,6 @@ func TestChannelDial(t *testing.T, s Server) { key := ari.NewKey(ari.ChannelKey, "c1") runTest("ok", t, s, func(t *testing.T, m *mock, cl ari.Client) { - m.Channel.On("Dial", key, "caller", 5*time.Second).Return(nil) err := cl.Channel().Dial(key, "caller", 5*time.Second) @@ -538,7 +518,6 @@ func TestChannelDial(t *testing.T, s Server) { }) runTest("err", t, s, func(t *testing.T, m *mock, cl ari.Client) { - m.Channel.On("Dial", key, "caller", 5*time.Second).Return(errors.New("error")) err := cl.Channel().Dial(key, "caller", 5*time.Second) @@ -556,7 +535,6 @@ func TestChannelHold(t *testing.T, s Server) { key := ari.NewKey(ari.ChannelKey, "c1") runTest("ok", t, s, func(t *testing.T, m *mock, cl ari.Client) { - m.Channel.On("Hold", key).Return(nil) err := cl.Channel().Hold(key) @@ -570,7 +548,6 @@ func TestChannelHold(t *testing.T, s Server) { }) runTest("err", t, s, func(t *testing.T, m *mock, cl ari.Client) { - m.Channel.On("Hold", key).Return(errors.New("error")) err := cl.Channel().Hold(key) @@ -588,7 +565,6 @@ func TestChannelStopHold(t *testing.T, s Server) { key := ari.NewKey(ari.ChannelKey, "c1") runTest("ok", t, s, func(t *testing.T, m *mock, cl ari.Client) { - m.Channel.On("StopHold", key).Return(nil) err := cl.Channel().StopHold(key) @@ -602,7 +578,6 @@ func TestChannelStopHold(t *testing.T, s Server) { }) runTest("err", t, s, func(t *testing.T, m *mock, cl ari.Client) { - m.Channel.On("StopHold", key).Return(errors.New("error")) err := cl.Channel().StopHold(key) @@ -620,7 +595,6 @@ func TestChannelRing(t *testing.T, s Server) { key := ari.NewKey(ari.ChannelKey, "c1") runTest("ok", t, s, func(t *testing.T, m *mock, cl ari.Client) { - m.Channel.On("Ring", key).Return(nil) err := cl.Channel().Ring(key) @@ -634,7 +608,6 @@ func TestChannelRing(t *testing.T, s Server) { }) runTest("err", t, s, func(t *testing.T, m *mock, cl ari.Client) { - m.Channel.On("Ring", key).Return(errors.New("error")) err := cl.Channel().Ring(key) @@ -652,7 +625,6 @@ func TestChannelSilence(t *testing.T, s Server) { key := ari.NewKey(ari.ChannelKey, "c1") runTest("ok", t, s, func(t *testing.T, m *mock, cl ari.Client) { - m.Channel.On("Silence", key).Return(nil) err := cl.Channel().Silence(key) @@ -666,7 +638,6 @@ func TestChannelSilence(t *testing.T, s Server) { }) runTest("err", t, s, func(t *testing.T, m *mock, cl ari.Client) { - m.Channel.On("Silence", key).Return(errors.New("error")) err := cl.Channel().Silence(key) @@ -684,7 +655,6 @@ func TestChannelStopSilence(t *testing.T, s Server) { key := ari.NewKey(ari.ChannelKey, "c1") runTest("ok", t, s, func(t *testing.T, m *mock, cl ari.Client) { - m.Channel.On("StopSilence", key).Return(nil) err := cl.Channel().StopSilence(key) @@ -698,7 +668,6 @@ func TestChannelStopSilence(t *testing.T, s Server) { }) runTest("err", t, s, func(t *testing.T, m *mock, cl ari.Client) { - m.Channel.On("StopSilence", key).Return(errors.New("error")) err := cl.Channel().StopSilence(key) @@ -716,7 +685,6 @@ func TestChannelStopRing(t *testing.T, s Server) { key := ari.NewKey(ari.ChannelKey, "c1") runTest("ok", t, s, func(t *testing.T, m *mock, cl ari.Client) { - m.Channel.On("StopRing", key).Return(nil) err := cl.Channel().StopRing(key) @@ -730,7 +698,6 @@ func TestChannelStopRing(t *testing.T, s Server) { }) runTest("err", t, s, func(t *testing.T, m *mock, cl ari.Client) { - m.Channel.On("StopRing", key).Return(errors.New("error")) err := cl.Channel().StopRing(key) @@ -748,8 +715,7 @@ func TestChannelOriginate(t *testing.T, s Server) { key := ari.NewKey(ari.ChannelKey, "c1") runTest("ok", t, s, func(t *testing.T, m *mock, cl ari.Client) { - - var expected = ari.NewChannelHandle(key, m.Channel, nil) + expected := ari.NewChannelHandle(key, m.Channel, nil) var req ari.OriginateRequest req.App = "App" @@ -773,7 +739,6 @@ func TestChannelOriginate(t *testing.T, s Server) { }) runTest("err", t, s, func(t *testing.T, m *mock, cl ari.Client) { - var req ari.OriginateRequest req.App = "App" req.ChannelID = "1234" @@ -802,9 +767,8 @@ func TestChannelPlay(t *testing.T, s Server) { cd.State = "Up" runTest("ok", t, s, func(t *testing.T, m *mock, cl ari.Client) { - pbkey := ari.NewKey(ari.PlaybackKey, "pb1") - var expected = ari.NewPlaybackHandle(pbkey, m.Playback, nil) + expected := ari.NewPlaybackHandle(pbkey, m.Playback, nil) m.Channel.On("Data", key).Return(&cd, nil) m.Channel.On("Play", key, "playbackID", "sound:hello").Return(expected, nil) @@ -825,9 +789,8 @@ func TestChannelPlay(t *testing.T, s Server) { }) runTest("no-id", t, s, func(t *testing.T, m *mock, cl ari.Client) { - pbkey := ari.NewKey(ari.PlaybackKey, "pb1") - var expected = ari.NewPlaybackHandle(pbkey, m.Playback, nil) + expected := ari.NewPlaybackHandle(pbkey, m.Playback, nil) m.Channel.On("Data", key).Return(&cd, nil) m.Channel.On("Play", key, nonEmpty, "sound:hello").Return(expected, nil) @@ -846,7 +809,6 @@ func TestChannelPlay(t *testing.T, s Server) { }) runTest("err", t, s, func(t *testing.T, m *mock, cl ari.Client) { - m.Channel.On("Data", key).Return(&cd, nil) m.Channel.On("Play", key, "playbackID", "sound:hello").Return(nil, errors.New("error")) @@ -868,11 +830,10 @@ func TestChannelRecord(t *testing.T, s Server) { key := ari.NewKey(ari.ChannelKey, "c1") runTest("ok", t, s, func(t *testing.T, m *mock, cl ari.Client) { - var opts *ari.RecordingOptions lrkey := ari.NewKey(ari.LiveRecordingKey, "lrh1") - var expected = ari.NewLiveRecordingHandle(lrkey, m.LiveRecording, nil) + expected := ari.NewLiveRecordingHandle(lrkey, m.LiveRecording, nil) m.Channel.On("Record", key, "recordid", opts).Return(expected, nil) @@ -892,11 +853,10 @@ func TestChannelRecord(t *testing.T, s Server) { }) runTest("no-id", t, s, func(t *testing.T, m *mock, cl ari.Client) { - var opts *ari.RecordingOptions lrkey := ari.NewKey(ari.LiveRecordingKey, "lrh1") - var expected = ari.NewLiveRecordingHandle(lrkey, m.LiveRecording, nil) + expected := ari.NewLiveRecordingHandle(lrkey, m.LiveRecording, nil) m.Channel.On("Record", key, nonEmpty, opts).Return(expected, nil) @@ -914,7 +874,6 @@ func TestChannelRecord(t *testing.T, s Server) { }) runTest("err", t, s, func(t *testing.T, m *mock, cl ari.Client) { - var opts *ari.RecordingOptions m.Channel.On("Record", key, "recordid", opts).Return(nil, errors.New("error")) @@ -937,11 +896,10 @@ func TestChannelSnoop(t *testing.T, s Server) { key := ari.NewKey(ari.ChannelKey, "c1") runTest("ok", t, s, func(t *testing.T, m *mock, cl ari.Client) { - var opts *ari.SnoopOptions chkey := ari.NewKey(ari.ChannelKey, "ch2") - var expected = ari.NewChannelHandle(chkey, m.Channel, nil) + expected := ari.NewChannelHandle(chkey, m.Channel, nil) m.Channel.On("Snoop", key, "snoopID", opts).Return(expected, nil) @@ -961,11 +919,10 @@ func TestChannelSnoop(t *testing.T, s Server) { }) runTest("no-id", t, s, func(t *testing.T, m *mock, cl ari.Client) { - var opts *ari.SnoopOptions chkey := ari.NewKey(ari.ChannelKey, "ch2") - var expected = ari.NewChannelHandle(chkey, m.Channel, nil) + expected := ari.NewChannelHandle(chkey, m.Channel, nil) m.Channel.On("Snoop", key, tmock.Anything, opts).Return(expected, nil) @@ -983,7 +940,6 @@ func TestChannelSnoop(t *testing.T, s Server) { }) runTest("err", t, s, func(t *testing.T, m *mock, cl ari.Client) { - var opts *ari.SnoopOptions m.Channel.On("Snoop", key, "ch2", opts).Return(nil, errors.New("error")) @@ -1002,11 +958,61 @@ func TestChannelSnoop(t *testing.T, s Server) { }) } +func TestChannelExternalMedia(t *testing.T, s Server) { + runTest("ok", t, s, func(t *testing.T, m *mock, cl ari.Client) { + key := ari.NewKey(ari.ChannelKey, rid.New(rid.Channel)) + + opts := ari.ExternalMediaOptions{ + ChannelID: key.ID, + App: cl.ApplicationName(), + ExternalHost: "localhost:1234", + Format: "slin16", + } + + m.Channel.On("ExternalMedia", nil, opts).Return(nil, errors.New("error")) + + h, err := cl.Channel().ExternalMedia(nil, opts) + if err != nil { + t.Errorf("error calling ExternalMedia: %v", err) + } else if h.ID() != key.ID { + t.Errorf("expected handle id '%s', got '%s'", key.ID, h.ID()) + } + + m.Shutdown() + + m.Channel.AssertCalled(t, "ExternalMedia", nil, opts) + }) + + runTest("err", t, s, func(t *testing.T, m *mock, cl ari.Client) { + key := ari.NewKey(ari.ChannelKey, rid.New(rid.Channel)) + + opts := ari.ExternalMediaOptions{ + ChannelID: key.ID, + App: cl.ApplicationName(), + ExternalHost: "localhost:1234", + // Format: "slin16", // Format is required + } + + m.Channel.On("ExternalMedia", nil, opts).Return(nil, errors.New("error")) + + h, err := cl.Channel().ExternalMedia(nil, opts) + if err == nil { + t.Error("expected error in ExternalMedia call, but got nil") + } + if h != nil { + t.Errorf("expected nil channel handle, but got key with ID: %s", h.ID()) + } + + m.Shutdown() + + m.Channel.AssertCalled(t, "ExternalMedia", nil, opts) + }) +} + func TestChannelSendDTMF(t *testing.T, s Server) { key := ari.NewKey(ari.ChannelKey, "c1") runTest("ok", t, s, func(t *testing.T, m *mock, cl ari.Client) { - m.Channel.On("SendDTMF", key, "1", &ari.DTMFOptions{}).Return(nil) err := cl.Channel().SendDTMF(key, "1", nil) @@ -1020,7 +1026,6 @@ func TestChannelSendDTMF(t *testing.T, s Server) { }) runTest("with-options", t, s, func(t *testing.T, m *mock, cl ari.Client) { - opts := &ari.DTMFOptions{ After: 4 * time.Second, } @@ -1038,7 +1043,6 @@ func TestChannelSendDTMF(t *testing.T, s Server) { }) runTest("err", t, s, func(t *testing.T, m *mock, cl ari.Client) { - m.Channel.On("SendDTMF", key, "1", &ari.DTMFOptions{}).Return(errors.New("err")) err := cl.Channel().SendDTMF(key, "1", nil) @@ -1050,13 +1054,10 @@ func TestChannelSendDTMF(t *testing.T, s Server) { m.Channel.AssertCalled(t, "SendDTMF", key, "1", &ari.DTMFOptions{}) }) - } func TestChannelVariableGet(t *testing.T, s Server) { - runTest("ok", t, s, func(t *testing.T, m *mock, cl ari.Client) { - m.Channel.On("GetVariable", &ari.Key{Kind: "", ID: "", Node: "", Dialog: "", App: ""}, "v1").Return("value", nil) val, err := cl.Channel().GetVariable(nil, "v1") @@ -1073,7 +1074,6 @@ func TestChannelVariableGet(t *testing.T, s Server) { }) runTest("err", t, s, func(t *testing.T, m *mock, cl ari.Client) { - m.Channel.On("GetVariable", &ari.Key{Kind: "", ID: "", Node: "", Dialog: "", App: ""}, "v1").Return("", errors.New("1")) val, err := cl.Channel().GetVariable(nil, "v1") @@ -1088,13 +1088,10 @@ func TestChannelVariableGet(t *testing.T, s Server) { m.Channel.AssertCalled(t, "GetVariable", &ari.Key{Kind: "", ID: "", Node: "", Dialog: "", App: ""}, "v1") }) - } func TestChannelVariableSet(t *testing.T, s Server) { - runTest("ok", t, s, func(t *testing.T, m *mock, cl ari.Client) { - m.Channel.On("SetVariable", &ari.Key{Kind: "", ID: "", Node: "", Dialog: "", App: ""}, "v1", "value").Return(nil) err := cl.Channel().SetVariable(nil, "v1", "value") @@ -1119,5 +1116,4 @@ func TestChannelVariableSet(t *testing.T, s Server) { m.Channel.AssertCalled(t, "SetVariable", &ari.Key{Kind: "", ID: "", Node: "", Dialog: "", App: ""}, "v1", "value") }) - } diff --git a/proxy/types.go b/proxy/types.go index 4d82961..170b6b6 100644 --- a/proxy/types.go +++ b/proxy/types.go @@ -114,18 +114,19 @@ type Request struct { BridgeRecord *BridgeRecord `json:"bridge_record,omitempty"` BridgeRemoveChannel *BridgeRemoveChannel `json:"bridge_remove_channel,omitempty"` - ChannelCreate *ChannelCreate `json:"channel_create,omitempty"` - ChannelContinue *ChannelContinue `json:"channel_continue,omitempty"` - ChannelDial *ChannelDial `json:"channel_dial,omitempty"` - ChannelHangup *ChannelHangup `json:"channel_hangup,omitempty"` - ChannelMOH *ChannelMOH `json:"channel_moh,omitempty"` - ChannelMute *ChannelMute `json:"channel_mute,omitempty"` - ChannelOriginate *ChannelOriginate `json:"channel_originate,omitempty"` - ChannelPlay *ChannelPlay `json:"channel_play,omitempty"` - ChannelRecord *ChannelRecord `json:"channel_record,omitempty"` - ChannelSendDTMF *ChannelSendDTMF `json:"channel_send_dtmf,omitempty"` - ChannelSnoop *ChannelSnoop `json:"channel_snoop,omitempty"` - ChannelVariable *ChannelVariable `json:"channel_variable,omitempty"` + ChannelCreate *ChannelCreate `json:"channel_create,omitempty"` + ChannelContinue *ChannelContinue `json:"channel_continue,omitempty"` + ChannelDial *ChannelDial `json:"channel_dial,omitempty"` + ChannelHangup *ChannelHangup `json:"channel_hangup,omitempty"` + ChannelMOH *ChannelMOH `json:"channel_moh,omitempty"` + ChannelMute *ChannelMute `json:"channel_mute,omitempty"` + ChannelOriginate *ChannelOriginate `json:"channel_originate,omitempty"` + ChannelPlay *ChannelPlay `json:"channel_play,omitempty"` + ChannelRecord *ChannelRecord `json:"channel_record,omitempty"` + ChannelSendDTMF *ChannelSendDTMF `json:"channel_send_dtmf,omitempty"` + ChannelSnoop *ChannelSnoop `json:"channel_snoop,omitempty"` + ChannelExternalMedia *ChannelExternalMedia `json:"channel_external_media,omitempty"` + ChannelVariable *ChannelVariable `json:"channel_variable,omitempty"` DeviceStateUpdate *DeviceStateUpdate `json:"device_state_update,omitempty"` @@ -299,6 +300,11 @@ type ChannelSnoop struct { Options *ari.SnoopOptions `json:"options,omitempty"` } +// ChannelExternalMedia describes the request for an external media channel +type ChannelExternalMedia struct { + Options ari.ExternalMediaOptions `json:"options"` +} + // ChannelVariable is the request type to read or modify a channel variable type ChannelVariable struct { // Name is the name of the channel variable diff --git a/server/channel.go b/server/channel.go index 33c6eac..aa12abb 100644 --- a/server/channel.go +++ b/server/channel.go @@ -2,6 +2,7 @@ package server import ( "context" + "errors" "github.com/CyCoreSystems/ari" "github.com/CyCoreSystems/ari-proxy/proxy" @@ -119,6 +120,10 @@ func (s *Server) channelMute(ctx context.Context, reply string, req *proxy.Reque } func (s *Server) channelOriginate(ctx context.Context, reply string, req *proxy.Request) { + if req.ChannelOriginate == nil { + s.sendError(reply, errors.New("OriginateRequest is mandatory")) + return + } orig := req.ChannelOriginate.OriginateRequest if orig.ChannelID == "" { @@ -150,6 +155,10 @@ func (s *Server) channelOriginate(ctx context.Context, reply string, req *proxy. } func (s *Server) channelStageOriginate(ctx context.Context, reply string, req *proxy.Request) { + if req.ChannelOriginate == nil { + s.sendError(reply, errors.New("OriginateRequest is mandatory")) + return + } orig := req.ChannelOriginate.OriginateRequest if orig.ChannelID == "" { @@ -304,6 +313,7 @@ func (s *Server) channelSnoop(ctx context.Context, reply string, req *proxy.Requ } func (s *Server) channelStageSnoop(ctx context.Context, reply string, req *proxy.Request) { + // Snoop requires a reference channel to exist data, err := s.ari.Channel().Data(req.Key) if err != nil || data == nil { s.sendError(reply, err) @@ -321,7 +331,58 @@ func (s *Server) channelStageSnoop(ctx context.Context, reply string, req *proxy s.publish(reply, &proxy.Response{ Key: s.ari.Channel().Get(ari.NewKey(ari.ChannelKey, req.ChannelSnoop.SnoopID)).Key(), }) +} + +func (s *Server) channelExternalMedia(ctx context.Context, reply string, req *proxy.Request) { + if req.ChannelExternalMedia == nil { + s.sendError(reply, errors.New("ExternalMediaOptions is required")) + return + } + opts := req.ChannelExternalMedia.Options + + if opts.ChannelID == "" { + opts.ChannelID = rid.New(rid.Channel) + } + + if req.Key != nil && req.Key.Dialog != "" { + s.Dialog.Bind(req.Key.Dialog, "channel", opts.ChannelID) + } + + h, err := s.ari.Channel().ExternalMedia(req.Key, opts) + if err != nil { + s.sendError(reply, err) + return + } + + s.publish(reply, &proxy.Response{ + Key: h.Key(), + }) +} + +func (s *Server) channelStageExternalMedia(ctx context.Context, reply string, req *proxy.Request) { + if req.ChannelExternalMedia == nil { + s.sendError(reply, errors.New("ExternalMediaOptions is required")) + return + } + opts := req.ChannelExternalMedia.Options + + if opts.ChannelID == "" { + opts.ChannelID = rid.New(rid.Channel) + } + + if req.Key != nil && req.Key.Dialog != "" { + s.Dialog.Bind(req.Key.Dialog, "channel", opts.ChannelID) + } + + h, err := s.ari.Channel().StageExternalMedia(req.Key, opts) + if err != nil { + s.sendError(reply, err) + return + } + s.publish(reply, &proxy.Response{ + Key: h.Key(), + }) } func (s *Server) channelStopHold(ctx context.Context, reply string, req *proxy.Request) { @@ -341,7 +402,6 @@ func (s *Server) channelStopSilence(ctx context.Context, reply string, req *prox } func (s *Server) channelSubscribe(ctx context.Context, reply string, req *proxy.Request) { - // bind dialog if req.Key.Dialog != "" { s.Dialog.Bind(req.Key.Dialog, "channel", req.Key.ID) diff --git a/server/channel_test.go b/server/channel_test.go index c5adaec..46ca28b 100644 --- a/server/channel_test.go +++ b/server/channel_test.go @@ -98,6 +98,10 @@ func TestChannelSnoop(t *testing.T) { integration.TestChannelSnoop(t, &srv{}) } +func TestChannelExternalMedia(t *testing.T) { + integration.TestChannelExternalMedia(t, &srv{}) +} + func TestChannelSendDTMF(t *testing.T) { integration.TestChannelSendDTMF(t, &srv{}) } diff --git a/server/server.go b/server/server.go index fe8a839..72f7cae 100644 --- a/server/server.go +++ b/server/server.go @@ -221,7 +221,7 @@ func (s *Server) listen(ctx context.Context) error { go s.runEventHandler(ctx) // TODO: run the dialog cleanup routine (remove bindings for entities which no longer exist) - //go s.runDialogCleaner(ctx) + // go s.runDialogCleaner(ctx) // Close the readyChannel to indicate that we are operational if s.readyCh != nil { @@ -440,6 +440,10 @@ func (s *Server) dispatchRequest(ctx context.Context, reply string, req *proxy.R f = s.channelSnoop case "ChannelStageSnoop": f = s.channelStageSnoop + case "ChannelExternalMedia": + f = s.channelExternalMedia + case "ChannelStageExternalMedia": + f = s.channelStageExternalMedia case "ChannelStopHold": f = s.channelStopHold case "ChannelStopMOH":