add sonos handler to play file
This commit is contained in:
+2
-1
@@ -1 +1,2 @@
|
||||
service*
|
||||
service*
|
||||
cert
|
||||
Vendored
+3
-1
@@ -13,7 +13,9 @@
|
||||
"env": {
|
||||
"HTTP_STATIC": "${workspaceFolder}/static/dist",
|
||||
"VIDEO_OUT_DEVICE": "/dev/video4",
|
||||
"AUDIO_OUT_DEVICE": "plughw:0,1,0"
|
||||
"AUDIO_OUT_DEVICE": "plughw:0,1,0",
|
||||
"INPUT_DEVICE": "/dev/input/event5",
|
||||
"JINGLE_PATH": "${workspaceFolder}/audio"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
Binary file not shown.
@@ -5,8 +5,10 @@ go 1.20
|
||||
require (
|
||||
github.com/alexflint/go-arg v1.4.3
|
||||
github.com/gin-gonic/gin v1.9.1
|
||||
github.com/holoplot/go-evdev v0.0.0-20230626094006-70c9462cc0f2
|
||||
github.com/pion/rtcp v1.2.10
|
||||
github.com/pion/webrtc/v3 v3.2.10
|
||||
github.com/szatmary/sonos v0.0.0-20191204204454-000c9219ff0e
|
||||
github.com/tinyzimmer/go-glib v0.0.25
|
||||
github.com/tinyzimmer/go-gst v0.2.33
|
||||
go.uber.org/zap v1.24.0
|
||||
|
||||
@@ -63,6 +63,8 @@ github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM=
|
||||
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/holoplot/go-evdev v0.0.0-20230626094006-70c9462cc0f2 h1:bxudnRpvfq2PMYEYN7VGj03+MXG4EobVUmONigCx1yA=
|
||||
github.com/holoplot/go-evdev v0.0.0-20230626094006-70c9462cc0f2/go.mod h1:iHAf8OIncO2gcQ8XOjS7CMJ2aPbX2Bs0wl5pZyanEqk=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
@@ -160,6 +162,8 @@ github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o
|
||||
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/szatmary/sonos v0.0.0-20191204204454-000c9219ff0e h1:beo21nzzdqCVGe6EdG3Lo3UbU7meQN4JjAAeyZccH94=
|
||||
github.com/szatmary/sonos v0.0.0-20191204204454-000c9219ff0e/go.mod h1:F5m1XEgf251EShYE9r+2Rl45NPLGovXttfuAjBb93bY=
|
||||
github.com/tinyzimmer/go-glib v0.0.25 h1:2GpumtkxA0wpXhCXP6D3ksb5pGMfo9WbhgLvEw8njK4=
|
||||
github.com/tinyzimmer/go-glib v0.0.25/go.mod h1:ltV0gO6xNFzZhsIRbFXv8RTq9NGoNT2dmAER4YmZfaM=
|
||||
github.com/tinyzimmer/go-gst v0.2.33 h1:wdwUYoN7dkWGUTrZIgB9Mp5LMRr/Sld5PVGRsE7/O9s=
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"syscall"
|
||||
|
||||
"github.com/kaedwen/webrtc/pkg/common"
|
||||
"github.com/kaedwen/webrtc/pkg/ring"
|
||||
"github.com/kaedwen/webrtc/pkg/server"
|
||||
"github.com/kaedwen/webrtc/pkg/webrtc"
|
||||
"github.com/tinyzimmer/go-glib/glib"
|
||||
@@ -26,7 +27,17 @@ func main() {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
http := server.NewHttpServer(lg.With(zap.String("context", "server")), &cfg.Http)
|
||||
http := server.NewHttpServer(lg.With(zap.String("context", "server")), &cfg)
|
||||
|
||||
rh, err := ring.NewRingHandler(lg.With(zap.String("context", "ring")), &cfg.Ring)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = rh.Watch(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = webrtc.NewWebrtcHandler(ctx, lg.With(zap.String("context", "webrtc")), cfg.Stream(), http.Hndl)
|
||||
if err != nil {
|
||||
|
||||
@@ -12,6 +12,7 @@ type Config struct {
|
||||
AudioOut ConfigAudioOutputStream `arg:"group:AudioOut"`
|
||||
AudioIn ConfigAudioInputStream `arg:"group:AudioIn"`
|
||||
Logging ConfigLogging `arg:"group:Logging"`
|
||||
Ring ConfigRing `arg:"group:Ring"`
|
||||
Http ConfigHTTP `arg:"group:Http"`
|
||||
}
|
||||
|
||||
@@ -25,6 +26,14 @@ type ConfigLogging struct {
|
||||
Level string `arg:"--log-level,env:LOG_LEVEL" default:"debug"`
|
||||
}
|
||||
|
||||
type ConfigRing struct {
|
||||
Device string `arg:"--input-device,env:INPUT_DEVICE" default:"/dev/input/by-path/platform-gpio-keys-user-event"`
|
||||
Key string `arg:"--ring-key" default:"KEY_F1"`
|
||||
JingleName string `arg:"--jingle-name,env:JINGLE_NAME" default:"ding-dong.wav"`
|
||||
JinglePath *string `arg:"--jingle-path,env:JINGLE_PATH"`
|
||||
SonosTarget string `arg:"--sonos-target,env:SONOS_TARGET" default:"Living Room"`
|
||||
}
|
||||
|
||||
type ConfigHTTP struct {
|
||||
Host string `arg:"--http-host,env:HTTP_HOST" default:"0.0.0.0"`
|
||||
Port uint `arg:"--http-port,env:HTTP_PORT" default:"8080"`
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
package ring
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/url"
|
||||
|
||||
"github.com/holoplot/go-evdev"
|
||||
"github.com/kaedwen/webrtc/pkg/common"
|
||||
"github.com/kaedwen/webrtc/pkg/ring/sonos"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type Player interface {
|
||||
Play(uri *url.URL) error
|
||||
}
|
||||
|
||||
type RingHandler struct {
|
||||
lg *zap.Logger
|
||||
cfg *common.ConfigRing
|
||||
players []Player
|
||||
}
|
||||
|
||||
func NewRingHandler(lg *zap.Logger, cfg *common.ConfigRing) (*RingHandler, error) {
|
||||
sp, err := sonos.NewSonosPlayer(lg.With(zap.String("context", "sonos")), cfg.SonosTarget)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &RingHandler{lg, cfg, []Player{sp}}, nil
|
||||
}
|
||||
|
||||
func (h *RingHandler) Watch(ctx context.Context) error {
|
||||
d, err := evdev.Open(h.cfg.Device)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
vMajor, vMinor, vMicro := d.DriverVersion()
|
||||
h.lg.Info("input driver running", zap.String("version", fmt.Sprintf("%d.%d.%d", vMajor, vMinor, vMicro)))
|
||||
|
||||
key := evdev.KEYFromString[h.cfg.Key]
|
||||
|
||||
bu := url.URL{
|
||||
Scheme: "http",
|
||||
Host: "192.168.60.141:9099",
|
||||
}
|
||||
|
||||
go func() {
|
||||
err := d.NonBlock()
|
||||
if err != nil {
|
||||
h.lg.Fatal("failed to set non block", zap.Error(err))
|
||||
}
|
||||
|
||||
for {
|
||||
e, err := d.ReadOne()
|
||||
if err == nil && e.Code == key && e.Value == 0 {
|
||||
tu := bu.JoinPath(h.cfg.JingleName)
|
||||
for _, p := range h.players {
|
||||
if err := p.Play(tu); err != nil {
|
||||
h.lg.Error("failed to play", zap.Error(err))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
<-ctx.Done()
|
||||
_ = d.Close()
|
||||
}()
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package sonos
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
so "github.com/szatmary/sonos"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type SonosPlayer struct {
|
||||
lg *zap.Logger
|
||||
zp *so.ZonePlayer
|
||||
}
|
||||
|
||||
func NewSonosPlayer(lg *zap.Logger, target string) (*SonosPlayer, error) {
|
||||
zp, err := SearchTarget(lg, target)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &SonosPlayer{lg, zp}, nil
|
||||
}
|
||||
|
||||
func (p *SonosPlayer) Play(uri *url.URL) error {
|
||||
err := p.zp.SetAVTransportURI(uri.String())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return p.zp.Play()
|
||||
}
|
||||
|
||||
func SearchTarget(lg *zap.Logger, target string) (*so.ZonePlayer, error) {
|
||||
son, err := so.NewSonos()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer son.Close()
|
||||
|
||||
found, _ := son.Search()
|
||||
to := time.After(10 * time.Second)
|
||||
for {
|
||||
select {
|
||||
case <-to:
|
||||
return nil, errors.New("timeout")
|
||||
case zp := <-found:
|
||||
lg.Info("found player", zap.String("name", zp.RoomName()))
|
||||
if zp.RoomName() == target {
|
||||
return zp, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+7
-7
@@ -25,7 +25,7 @@ type SignalingHandle struct {
|
||||
type HttpServer struct {
|
||||
http.Server
|
||||
lg *zap.Logger
|
||||
cfg *common.ConfigHTTP
|
||||
cfg *common.Config
|
||||
Hndl chan *SignalingHandle
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ func NewSignalingHandle(id string) SignalingHandle {
|
||||
}
|
||||
}
|
||||
|
||||
func NewHttpServer(lg *zap.Logger, cfg *common.ConfigHTTP) *HttpServer {
|
||||
func NewHttpServer(lg *zap.Logger, cfg *common.Config) *HttpServer {
|
||||
h := HttpServer{
|
||||
Hndl: make(chan *SignalingHandle, 10),
|
||||
cfg: cfg,
|
||||
@@ -57,12 +57,12 @@ func NewHttpServer(lg *zap.Logger, cfg *common.ConfigHTTP) *HttpServer {
|
||||
}
|
||||
|
||||
func (h *HttpServer) ListenAndServe(ctx context.Context) error {
|
||||
if h.cfg.Tls {
|
||||
if h.cfg.Http.Tls {
|
||||
// set the configured address
|
||||
h.Addr = h.cfg.Address()
|
||||
h.Addr = h.cfg.Http.Address()
|
||||
|
||||
if h.cfg.TlsCert != nil && h.cfg.TlsKey != nil {
|
||||
cert, err := tls.LoadX509KeyPair(*h.cfg.TlsCert, *h.cfg.TlsKey)
|
||||
if h.cfg.Http.TlsCert != nil && h.cfg.Http.TlsKey != nil {
|
||||
cert, err := tls.LoadX509KeyPair(*h.cfg.Http.TlsCert, *h.cfg.Http.TlsKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -94,7 +94,7 @@ func (h *HttpServer) ListenAndServe(ctx context.Context) error {
|
||||
}()
|
||||
} else {
|
||||
// set the configured address
|
||||
h.Addr = h.cfg.Address()
|
||||
h.Addr = h.cfg.Http.Address()
|
||||
|
||||
go func() {
|
||||
// and listen
|
||||
|
||||
+9
-3
@@ -38,9 +38,15 @@ func (s staticDiskSource) Open(p string) (common.StaticSourceFile, error) {
|
||||
return &staticSourceFile{t}, nil
|
||||
}
|
||||
|
||||
func SetupHandler(e *gin.Engine, cfg *common.ConfigHTTP) {
|
||||
if cfg.StaticPath != nil {
|
||||
handler := common.NewStaticHandler(staticDiskSource{*cfg.StaticPath}, "index.html")
|
||||
func SetupHandler(e *gin.Engine, cfg *common.Config) {
|
||||
if cfg.Ring.JinglePath != nil {
|
||||
e.GET(cfg.Ring.JingleName, func(c *gin.Context) {
|
||||
c.File(path.Join(*cfg.Ring.JinglePath, cfg.Ring.JingleName))
|
||||
})
|
||||
}
|
||||
|
||||
if cfg.Http.StaticPath != nil {
|
||||
handler := common.NewStaticHandler(staticDiskSource{*cfg.Http.StaticPath}, "index.html")
|
||||
e.NoRoute(func(c *gin.Context) {
|
||||
encoding := c.Request.Header.Get("Accept-Encoding")
|
||||
|
||||
|
||||
+7
-1
@@ -41,7 +41,13 @@ func (s staticSource) Open(p string) (common.StaticSourceFile, error) {
|
||||
return &staticSourceFile{t}, nil
|
||||
}
|
||||
|
||||
func SetupHandler(e *gin.Engine, _ *common.ConfigHTTP) {
|
||||
func SetupHandler(e *gin.Engine, cfg *common.Config) {
|
||||
if cfg.Ring.JinglePath != nil {
|
||||
e.GET(cfg.Ring.JingleName, func(c *gin.Context) {
|
||||
c.File(path.Join(*cfg.Ring.JinglePath, cfg.Ring.JingleName))
|
||||
})
|
||||
}
|
||||
|
||||
handler := common.NewStaticHandler(staticSource{"dist"}, "index.html")
|
||||
e.NoRoute(func(c *gin.Context) {
|
||||
encoding := c.Request.Header.Get("Accept-Encoding")
|
||||
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
/evtest
|
||||
/uinputtest
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 Holoplot GmbH
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
# Go support for the Linux evdev interface
|
||||
|
||||
This is a pure Go package for the Linux evdev interface, without cgo dependencies.
|
||||
|
||||
The Linux evdev interface is the userspace interface to interact with input devices such as
|
||||
keyboard, mice, joysticks, touchscreens, rotary encoders etc.
|
||||
|
||||
The implementation in this package has the following features:
|
||||
|
||||
* Query device information such as the name, the physical location, the unique ID,
|
||||
the vendor/product/bus/version IDs
|
||||
* Query supported event types, codes and device properties
|
||||
* Query the current status of bit-field based input types (such as keyboard, switches etc)
|
||||
as well as information on absolute types (`ABS_X`, ...) including their min/max values and
|
||||
current state
|
||||
* Grab/Ungrab/Revoke support for exclusive claiming of devices
|
||||
* Auto-generated `const` definitions and maps for types and codes from the kernel include headers
|
||||
|
||||
# Install
|
||||
|
||||
```
|
||||
go get github.com/holoplot/go-evdev
|
||||
```
|
||||
|
||||
And then use it in your source code.
|
||||
|
||||
```
|
||||
import "github.com/holoplot/go-evdev"
|
||||
```
|
||||
|
||||
# Re-generating codes.go
|
||||
|
||||
To re-generate `codes.go` from the latest kernel headers, use the following command.
|
||||
|
||||
```
|
||||
go run build/gen-codes/main.go
|
||||
gofmt codes.go
|
||||
```
|
||||
|
||||
You can optionally validate generated string mappings with `go run build/gen-codes-validate/main.go`
|
||||
|
||||
# Example
|
||||
|
||||
See the code in `cmd/evtest` for an example.
|
||||
|
||||
# MIT License
|
||||
|
||||
See file `LICENSE` for details.
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
package evdev
|
||||
|
||||
type bitmap struct {
|
||||
bits []byte
|
||||
}
|
||||
|
||||
func (bm *bitmap) bitIsSet(bit int) bool {
|
||||
if bit > len(bm.bits)*8 {
|
||||
return false
|
||||
}
|
||||
|
||||
return bm.bits[bit/8]&(1<<(bit%8)) != 0
|
||||
}
|
||||
|
||||
func (bm *bitmap) setBits() []int {
|
||||
var a []int
|
||||
|
||||
for i, by := range bm.bits {
|
||||
for bit := 0; bit < 8; bit++ {
|
||||
if by&byte(1<<bit) != 0 {
|
||||
a = append(a, (i*8)+bit)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return a
|
||||
}
|
||||
|
||||
func newBitmap(bits []byte) *bitmap {
|
||||
return &bitmap{
|
||||
bits: bits,
|
||||
}
|
||||
}
|
||||
+3751
File diff suppressed because it is too large
Load Diff
+261
@@ -0,0 +1,261 @@
|
||||
package evdev
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"os"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// InputDevice represent a Linux kernel input device in userspace.
|
||||
// It can be used to query and write device properties, read input events,
|
||||
// or grab it for exclusive access.
|
||||
type InputDevice struct {
|
||||
file *os.File
|
||||
driverVersion int32
|
||||
}
|
||||
|
||||
// Open creates a new InputDevice from the given path. Returns an error if
|
||||
// the device node could not be opened or its properties failed to read.
|
||||
func Open(path string) (*InputDevice, error) {
|
||||
d := &InputDevice{}
|
||||
|
||||
var err error
|
||||
d.file, err = os.OpenFile(path, os.O_RDWR, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
d.driverVersion, err = ioctlEVIOCGVERSION(d.file.Fd())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot get driver version: %v", err)
|
||||
}
|
||||
|
||||
return d, nil
|
||||
}
|
||||
|
||||
// OpenByName creates a new InputDevice from the device name as reported by the kernel.
|
||||
// Returns an error if the name does not exist, or the device node could
|
||||
// not be opened or its properties failed to read.
|
||||
func OpenByName(name string) (*InputDevice, error) {
|
||||
devices, err := ListDevicePaths()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, d := range devices {
|
||||
if d.Name == name {
|
||||
return Open(d.Path)
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("could not find input device with name %q", name)
|
||||
}
|
||||
|
||||
// Close releases the resources held by an InputDevice. After calling this
|
||||
// function, the InputDevice is no longer operational.
|
||||
func (d *InputDevice) Close() error {
|
||||
return d.file.Close()
|
||||
}
|
||||
|
||||
// Path returns the device's node path it was opened under.
|
||||
func (d *InputDevice) Path() string {
|
||||
return d.file.Name()
|
||||
}
|
||||
|
||||
// DriverVersion returns the version of the Linux Evdev driver.
|
||||
// The three ints returned by this function describe the major, minor and
|
||||
// micro parts of the version code.
|
||||
func (d *InputDevice) DriverVersion() (int, int, int) {
|
||||
return int(d.driverVersion >> 16),
|
||||
int((d.driverVersion >> 8) & 0xff),
|
||||
int((d.driverVersion >> 0) & 0xff)
|
||||
}
|
||||
|
||||
// Name returns the device's name as reported by the kernel.
|
||||
func (d *InputDevice) Name() (string, error) {
|
||||
return ioctlEVIOCGNAME(d.file.Fd())
|
||||
}
|
||||
|
||||
// PhysicalLocation returns the device's physical location as reported by the kernel.
|
||||
func (d *InputDevice) PhysicalLocation() (string, error) {
|
||||
return ioctlEVIOCGPHYS(d.file.Fd())
|
||||
}
|
||||
|
||||
// UniqueID returns the device's unique identifier as reported by the kernel.
|
||||
func (d *InputDevice) UniqueID() (string, error) {
|
||||
return ioctlEVIOCGUNIQ(d.file.Fd())
|
||||
}
|
||||
|
||||
// InputID returns the device's vendor/product/busType/version information as reported by the kernel.
|
||||
func (d *InputDevice) InputID() (InputID, error) {
|
||||
return ioctlEVIOCGID(d.file.Fd())
|
||||
}
|
||||
|
||||
// CapableTypes returns a slice of EvType that are the device supports
|
||||
func (d *InputDevice) CapableTypes() []EvType {
|
||||
var types []EvType
|
||||
|
||||
evBits, err := ioctlEVIOCGBIT(d.file.Fd(), 0)
|
||||
if err != nil {
|
||||
return []EvType{}
|
||||
}
|
||||
|
||||
evBitmap := newBitmap(evBits)
|
||||
|
||||
for _, t := range evBitmap.setBits() {
|
||||
types = append(types, EvType(t))
|
||||
}
|
||||
|
||||
return types
|
||||
}
|
||||
|
||||
// CapableEvents returns a slice of EvCode that are the device supports for given EvType
|
||||
func (d *InputDevice) CapableEvents(t EvType) []EvCode {
|
||||
var codes []EvCode
|
||||
|
||||
evBits, err := ioctlEVIOCGBIT(d.file.Fd(), int(t))
|
||||
if err != nil {
|
||||
return []EvCode{}
|
||||
}
|
||||
|
||||
evBitmap := newBitmap(evBits)
|
||||
|
||||
for _, t := range evBitmap.setBits() {
|
||||
codes = append(codes, EvCode(t))
|
||||
}
|
||||
|
||||
return codes
|
||||
}
|
||||
|
||||
// Properties returns a slice of EvProp that are the device supports
|
||||
func (d *InputDevice) Properties() []EvProp {
|
||||
var props []EvProp
|
||||
|
||||
propBits, err := ioctlEVIOCGPROP(d.file.Fd())
|
||||
if err != nil {
|
||||
return []EvProp{}
|
||||
}
|
||||
|
||||
propBitmap := newBitmap(propBits)
|
||||
|
||||
for _, p := range propBitmap.setBits() {
|
||||
props = append(props, EvProp(p))
|
||||
}
|
||||
|
||||
return props
|
||||
}
|
||||
|
||||
// State return a StateMap for the given type. The map will be empty if the requested type
|
||||
// is not supported by the device.
|
||||
func (d *InputDevice) State(t EvType) (StateMap, error) {
|
||||
fd := d.file.Fd()
|
||||
|
||||
evBits, err := ioctlEVIOCGBIT(fd, 0)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot get evBits: %v", err)
|
||||
}
|
||||
|
||||
evBitmap := newBitmap(evBits)
|
||||
|
||||
if !evBitmap.bitIsSet(int(t)) {
|
||||
return StateMap{}, nil
|
||||
}
|
||||
|
||||
codeBits, err := ioctlEVIOCGBIT(fd, int(t))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot get evBits: %v", err)
|
||||
}
|
||||
|
||||
codeBitmap := newBitmap(codeBits)
|
||||
|
||||
var stateBits []byte
|
||||
|
||||
switch t {
|
||||
case EV_KEY:
|
||||
stateBits, err = ioctlEVIOCGKEY(fd)
|
||||
case EV_SW:
|
||||
stateBits, err = ioctlEVIOCGSW(fd)
|
||||
case EV_LED:
|
||||
stateBits, err = ioctlEVIOCGLED(fd)
|
||||
case EV_SND:
|
||||
stateBits, err = ioctlEVIOCGSND(fd)
|
||||
default:
|
||||
err = fmt.Errorf("unsupported evType %d", t)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
stateBitmap := newBitmap(stateBits)
|
||||
st := StateMap{}
|
||||
|
||||
for _, code := range codeBitmap.setBits() {
|
||||
st[EvCode(code)] = stateBitmap.bitIsSet(code)
|
||||
}
|
||||
|
||||
return st, nil
|
||||
}
|
||||
|
||||
// AbsInfos returns the AbsInfo struct for all axis the device supports.
|
||||
func (d *InputDevice) AbsInfos() (map[EvCode]AbsInfo, error) {
|
||||
a := make(map[EvCode]AbsInfo)
|
||||
|
||||
absBits, err := ioctlEVIOCGBIT(d.file.Fd(), EV_ABS)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot get absBits: %v", err)
|
||||
}
|
||||
|
||||
absBitmap := newBitmap(absBits)
|
||||
|
||||
for _, abs := range absBitmap.setBits() {
|
||||
absInfo, err := ioctlEVIOCGABS(d.file.Fd(), abs)
|
||||
if err == nil {
|
||||
a[EvCode(abs)] = absInfo
|
||||
}
|
||||
}
|
||||
|
||||
return a, nil
|
||||
}
|
||||
|
||||
// Grab grabs the device for exclusive access. No other process will receive
|
||||
// input events until the device instance is active.
|
||||
func (d *InputDevice) Grab() error {
|
||||
return ioctlEVIOCGRAB(d.file.Fd(), 1)
|
||||
}
|
||||
|
||||
// Ungrab releases a previously taken exclusive use with Grab().
|
||||
func (d *InputDevice) Ungrab() error {
|
||||
return ioctlEVIOCGRAB(d.file.Fd(), 0)
|
||||
}
|
||||
|
||||
// Revoke revokes device access
|
||||
func (d *InputDevice) Revoke() error {
|
||||
return ioctlEVIOCREVOKE(d.file.Fd())
|
||||
}
|
||||
|
||||
// NonBlock sets file descriptor into nonblocking mode.
|
||||
// This way it is possible to interrupt ReadOne call by closing the device.
|
||||
// Note: file.Fd() call will set file descriptor back to blocking mode so make sure your program
|
||||
// is not using any other method than ReadOne after NonBlock call.
|
||||
func (d *InputDevice) NonBlock() error {
|
||||
return syscall.SetNonblock(int(d.file.Fd()), true)
|
||||
}
|
||||
|
||||
// ReadOne reads one InputEvent from the device. It blocks until an event has
|
||||
// been received or an error has occurred.
|
||||
func (d *InputDevice) ReadOne() (*InputEvent, error) {
|
||||
event := InputEvent{}
|
||||
|
||||
err := binary.Read(d.file, binary.LittleEndian, &event)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &event, nil
|
||||
}
|
||||
|
||||
// WriteOne writes one InputEvent to the device.
|
||||
// Useful for controlling LEDs of the device
|
||||
func (d *InputDevice) WriteOne(event *InputEvent) error {
|
||||
return binary.Write(d.file, binary.LittleEndian, event)
|
||||
}
|
||||
+274
@@ -0,0 +1,274 @@
|
||||
package evdev
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
ioctlDirNone = 0x0
|
||||
ioctlDirWrite = 0x1
|
||||
ioctlDirRead = 0x2
|
||||
)
|
||||
|
||||
func trimNull(s string) string {
|
||||
return strings.Trim(s, "\x00")
|
||||
}
|
||||
|
||||
func ioctlMakeCode(dir, typ, nr int, size uintptr) uint32 {
|
||||
var code uint32
|
||||
if dir > ioctlDirWrite|ioctlDirRead {
|
||||
panic(fmt.Errorf("invalid ioctl dir value: %d", dir))
|
||||
}
|
||||
|
||||
if size > 1<<14 {
|
||||
panic(fmt.Errorf("invalid ioctl size value: %d", size))
|
||||
}
|
||||
|
||||
code |= uint32(dir) << 30
|
||||
code |= uint32(size) << 16
|
||||
code |= uint32(typ) << 8
|
||||
code |= uint32(nr)
|
||||
|
||||
return code
|
||||
}
|
||||
|
||||
func doIoctl(fd uintptr, code uint32, ptr unsafe.Pointer) error {
|
||||
_, _, errno := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(code), uintptr(ptr))
|
||||
if errno != 0 {
|
||||
return errors.New(errno.Error())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func ioctlEVIOCGVERSION(fd uintptr) (int32, error) {
|
||||
version := int32(0)
|
||||
code := ioctlMakeCode(ioctlDirRead, 'E', 0x01, unsafe.Sizeof(version))
|
||||
err := doIoctl(fd, code, unsafe.Pointer(&version))
|
||||
return version, err
|
||||
}
|
||||
|
||||
func ioctlEVIOCGID(fd uintptr) (InputID, error) {
|
||||
id := InputID{}
|
||||
code := ioctlMakeCode(ioctlDirRead, 'E', 0x02, unsafe.Sizeof(id))
|
||||
err := doIoctl(fd, code, unsafe.Pointer(&id))
|
||||
return id, err
|
||||
}
|
||||
|
||||
func ioctlEVIOCGREP(fd uintptr) ([2]uint32, error) {
|
||||
rep := [2]uint32{}
|
||||
code := ioctlMakeCode(ioctlDirRead, 'E', 0x03, unsafe.Sizeof(rep))
|
||||
err := doIoctl(fd, code, unsafe.Pointer(&rep))
|
||||
return rep, err
|
||||
}
|
||||
|
||||
func ioctlEVIOCSREP(fd uintptr, rep [2]uint32) error {
|
||||
code := ioctlMakeCode(ioctlDirWrite, 'E', 0x03, unsafe.Sizeof(rep))
|
||||
return doIoctl(fd, code, unsafe.Pointer(&rep))
|
||||
}
|
||||
|
||||
func ioctlEVIOCGKEYCODE(fd uintptr) (InputKeymapEntry, error) {
|
||||
entry := InputKeymapEntry{}
|
||||
code := ioctlMakeCode(ioctlDirRead, 'E', 0x04, unsafe.Sizeof(entry))
|
||||
err := doIoctl(fd, code, unsafe.Pointer(&entry))
|
||||
return entry, err
|
||||
}
|
||||
|
||||
func ioctlEVIOCSKEYCODE(fd uintptr, entry InputKeymapEntry) error {
|
||||
code := ioctlMakeCode(ioctlDirWrite, 'E', 0x04, unsafe.Sizeof(entry))
|
||||
return doIoctl(fd, code, unsafe.Pointer(&entry))
|
||||
}
|
||||
|
||||
func ioctlEVIOCGNAME(fd uintptr) (string, error) {
|
||||
str := [256]byte{}
|
||||
code := ioctlMakeCode(ioctlDirRead, 'E', 0x06, unsafe.Sizeof(str))
|
||||
err := doIoctl(fd, code, unsafe.Pointer(&str))
|
||||
return trimNull(string(str[:])), err
|
||||
}
|
||||
|
||||
func ioctlEVIOCGPHYS(fd uintptr) (string, error) {
|
||||
str := [256]byte{}
|
||||
code := ioctlMakeCode(ioctlDirRead, 'E', 0x07, unsafe.Sizeof(str))
|
||||
err := doIoctl(fd, code, unsafe.Pointer(&str))
|
||||
return trimNull(string(str[:])), err
|
||||
}
|
||||
|
||||
func ioctlEVIOCGUNIQ(fd uintptr) (string, error) {
|
||||
str := [256]byte{}
|
||||
code := ioctlMakeCode(ioctlDirRead, 'E', 0x08, unsafe.Sizeof(str))
|
||||
err := doIoctl(fd, code, unsafe.Pointer(&str))
|
||||
return trimNull(string(str[:])), err
|
||||
}
|
||||
|
||||
func ioctlEVIOCGPROP(fd uintptr) ([]byte, error) {
|
||||
bits := [256]byte{}
|
||||
code := ioctlMakeCode(ioctlDirRead, 'E', 0x09, unsafe.Sizeof(bits))
|
||||
err := doIoctl(fd, code, unsafe.Pointer(&bits))
|
||||
return bits[:], err
|
||||
}
|
||||
|
||||
func ioctlEVIOCGKEY(fd uintptr) ([]byte, error) {
|
||||
bits := [KEY_MAX]byte{}
|
||||
code := ioctlMakeCode(ioctlDirRead, 'E', 0x18, unsafe.Sizeof(bits))
|
||||
err := doIoctl(fd, code, unsafe.Pointer(&bits))
|
||||
return bits[:], err
|
||||
}
|
||||
|
||||
func ioctlEVIOCGLED(fd uintptr) ([]byte, error) {
|
||||
bits := [LED_MAX]byte{}
|
||||
code := ioctlMakeCode(ioctlDirRead, 'E', 0x19, unsafe.Sizeof(bits))
|
||||
err := doIoctl(fd, code, unsafe.Pointer(&bits))
|
||||
return bits[:], err
|
||||
}
|
||||
|
||||
func ioctlEVIOCGSND(fd uintptr) ([]byte, error) {
|
||||
bits := [SND_MAX]byte{}
|
||||
code := ioctlMakeCode(ioctlDirRead, 'E', 0x1a, unsafe.Sizeof(bits))
|
||||
err := doIoctl(fd, code, unsafe.Pointer(&bits))
|
||||
return bits[:], err
|
||||
}
|
||||
|
||||
func ioctlEVIOCGSW(fd uintptr) ([]byte, error) {
|
||||
bits := [SW_MAX]byte{}
|
||||
code := ioctlMakeCode(ioctlDirRead, 'E', 0x1b, unsafe.Sizeof(bits))
|
||||
err := doIoctl(fd, code, unsafe.Pointer(&bits))
|
||||
return bits[:], err
|
||||
}
|
||||
|
||||
func ioctlEVIOCGBIT(fd uintptr, evtype int) ([]byte, error) {
|
||||
var cnt int
|
||||
|
||||
switch evtype {
|
||||
case 0:
|
||||
// special case, indicating the list of all feature types supported should be returned,
|
||||
// rather than the list of particular features for that type
|
||||
cnt = EV_CNT
|
||||
case EV_KEY:
|
||||
cnt = KEY_CNT
|
||||
case EV_REL:
|
||||
cnt = REL_CNT
|
||||
case EV_ABS:
|
||||
cnt = ABS_CNT
|
||||
case EV_MSC:
|
||||
cnt = MSC_CNT
|
||||
case EV_SW:
|
||||
cnt = SW_CNT
|
||||
case EV_LED:
|
||||
cnt = LED_CNT
|
||||
case EV_SND:
|
||||
cnt = SND_CNT
|
||||
case EV_REP:
|
||||
cnt = REP_CNT
|
||||
case EV_FF:
|
||||
cnt = FF_CNT
|
||||
default: // EV_PWR, EV_FF_STATUS ??
|
||||
cnt = KEY_MAX
|
||||
}
|
||||
|
||||
bytesNumber := (cnt + 7) / 8
|
||||
|
||||
bits := [KEY_MAX]byte{}
|
||||
code := ioctlMakeCode(ioctlDirRead, 'E', 0x20+evtype, unsafe.Sizeof(bits))
|
||||
err := doIoctl(fd, code, unsafe.Pointer(&bits))
|
||||
return bits[:bytesNumber], err
|
||||
}
|
||||
|
||||
func ioctlEVIOCGABS(fd uintptr, abs int) (AbsInfo, error) {
|
||||
info := AbsInfo{}
|
||||
code := ioctlMakeCode(ioctlDirRead, 'E', 0x40+abs, unsafe.Sizeof(info))
|
||||
err := doIoctl(fd, code, unsafe.Pointer(&info))
|
||||
return info, err
|
||||
}
|
||||
|
||||
func ioctlEVIOCSABS(fd uintptr, abs int, info AbsInfo) error {
|
||||
code := ioctlMakeCode(ioctlDirWrite, 'E', 0xc0+abs, unsafe.Sizeof(info))
|
||||
return doIoctl(fd, code, unsafe.Pointer(&info))
|
||||
}
|
||||
|
||||
func ioctlEVIOCGRAB(fd uintptr, p int32) error {
|
||||
code := ioctlMakeCode(ioctlDirWrite, 'E', 0x90, unsafe.Sizeof(p))
|
||||
if p != 0 {
|
||||
return doIoctl(fd, code, unsafe.Pointer(&p))
|
||||
}
|
||||
return doIoctl(fd, code, nil)
|
||||
}
|
||||
|
||||
func ioctlEVIOCREVOKE(fd uintptr) error {
|
||||
var p int32
|
||||
code := ioctlMakeCode(ioctlDirWrite, 'E', 0x91, unsafe.Sizeof(p))
|
||||
return doIoctl(fd, code, nil)
|
||||
}
|
||||
|
||||
func ioctlUISETEVBIT(fd uintptr, ev uintptr) error {
|
||||
var p int32
|
||||
code := ioctlMakeCode(ioctlDirWrite, 'U', 100, unsafe.Sizeof(p))
|
||||
return doIoctl(fd, code, unsafe.Pointer(ev))
|
||||
}
|
||||
|
||||
func ioctlUISETKEYBIT(fd uintptr, key uintptr) error {
|
||||
var p int32
|
||||
code := ioctlMakeCode(ioctlDirWrite, 'U', 101, unsafe.Sizeof(p))
|
||||
return doIoctl(fd, code, unsafe.Pointer(key))
|
||||
}
|
||||
|
||||
func ioctlUISETRELBIT(fd uintptr, rel uintptr) error {
|
||||
var p int32
|
||||
code := ioctlMakeCode(ioctlDirWrite, 'U', 102, unsafe.Sizeof(p))
|
||||
return doIoctl(fd, code, unsafe.Pointer(rel))
|
||||
}
|
||||
|
||||
func ioctlUISETABSBIT(fd uintptr, abs uintptr) error {
|
||||
var p int32
|
||||
code := ioctlMakeCode(ioctlDirWrite, 'U', 103, unsafe.Sizeof(p))
|
||||
return doIoctl(fd, code, unsafe.Pointer(abs))
|
||||
}
|
||||
|
||||
func ioctlUISETMSCBIT(fd uintptr, msc uintptr) error {
|
||||
var p int32
|
||||
code := ioctlMakeCode(ioctlDirWrite, 'U', 104, unsafe.Sizeof(p))
|
||||
return doIoctl(fd, code, unsafe.Pointer(msc))
|
||||
}
|
||||
|
||||
func ioctlUISETLEDBIT(fd uintptr, led uintptr) error {
|
||||
var p int32
|
||||
code := ioctlMakeCode(ioctlDirWrite, 'U', 105, unsafe.Sizeof(p))
|
||||
return doIoctl(fd, code, unsafe.Pointer(led))
|
||||
}
|
||||
|
||||
func ioctlUISETSNDBIT(fd uintptr, snd uintptr) error {
|
||||
var p int32
|
||||
code := ioctlMakeCode(ioctlDirWrite, 'U', 106, unsafe.Sizeof(p))
|
||||
return doIoctl(fd, code, unsafe.Pointer(snd))
|
||||
}
|
||||
|
||||
func ioctlUISETFFBIT(fd uintptr, fe uintptr) error {
|
||||
var p int32
|
||||
code := ioctlMakeCode(ioctlDirWrite, 'U', 107, unsafe.Sizeof(p))
|
||||
return doIoctl(fd, code, unsafe.Pointer(fe))
|
||||
}
|
||||
|
||||
func ioctlUISETSWBIT(fd uintptr, sw uintptr) error {
|
||||
var p int32
|
||||
code := ioctlMakeCode(ioctlDirWrite, 'U', 109, unsafe.Sizeof(p))
|
||||
return doIoctl(fd, code, unsafe.Pointer(sw))
|
||||
}
|
||||
|
||||
func ioctlUISETPROPBIT(fd uintptr, prop uintptr) error {
|
||||
var p int32
|
||||
code := ioctlMakeCode(ioctlDirWrite, 'U', 110, unsafe.Sizeof(p))
|
||||
return doIoctl(fd, code, unsafe.Pointer(prop))
|
||||
}
|
||||
|
||||
func ioctlUIDEVCREATE(fd uintptr) error {
|
||||
code := ioctlMakeCode(ioctlDirNone, 'U', 1, 0)
|
||||
return doIoctl(fd, code, nil)
|
||||
}
|
||||
|
||||
func ioctlUIDEVDESTROY(fd uintptr) error {
|
||||
code := ioctlMakeCode(ioctlDirNone, 'U', 2, 0)
|
||||
return doIoctl(fd, code, nil)
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
package evdev
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
// InputPath contains information about an InputDevice Name & Path
|
||||
type InputPath struct {
|
||||
Name string
|
||||
Path string
|
||||
}
|
||||
|
||||
// ListDevicePaths lists all available input devices, returning their
|
||||
// filename path, and the name as reported by the kernel.
|
||||
func ListDevicePaths() ([]InputPath, error) {
|
||||
var list []InputPath
|
||||
|
||||
basePath := "/dev/input"
|
||||
|
||||
files, err := ioutil.ReadDir(basePath)
|
||||
if err != nil {
|
||||
return list, err
|
||||
}
|
||||
|
||||
for _, fileName := range files {
|
||||
if fileName.IsDir() {
|
||||
continue
|
||||
}
|
||||
|
||||
full := fmt.Sprintf("%s/%s", basePath, fileName.Name())
|
||||
if d, err := Open(full); err == nil {
|
||||
name, _ := d.Name()
|
||||
list = append(list, InputPath{Name: name, Path: d.Path()})
|
||||
d.Close()
|
||||
}
|
||||
}
|
||||
return list, nil
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
package evdev
|
||||
|
||||
var EvCodeNameLookup = map[EvType]map[EvCode]string{
|
||||
EV_SYN: SYNNames,
|
||||
EV_KEY: KEYNames,
|
||||
EV_REL: RELNames,
|
||||
EV_ABS: ABSNames,
|
||||
EV_MSC: MSCNames,
|
||||
EV_SW: SWNames,
|
||||
EV_LED: LEDNames,
|
||||
EV_SND: SNDNames,
|
||||
EV_REP: REPNames,
|
||||
EV_FF: FFNames,
|
||||
// EV_PWR:
|
||||
// EV_FF_STATUS:
|
||||
}
|
||||
|
||||
// TypeName returns the name of an EvType as string, or "UNKNOWN" if the type is not valid
|
||||
func TypeName(t EvType) string {
|
||||
name, ok := EVToString[t]
|
||||
if ok {
|
||||
return name
|
||||
}
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
// PropName returns the name of the given EvProp, or "UNKNOWN" if the property is not valid
|
||||
func PropName(p EvProp) string {
|
||||
name, ok := INPUTToString[p]
|
||||
if ok {
|
||||
return name
|
||||
}
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
// CodeName returns the name of an EvfCode in the given EvType, or "UNKNOWN" of the code is not valid.
|
||||
func CodeName(t EvType, c EvCode) string {
|
||||
name, ok := EvCodeNameLookup[t][c]
|
||||
if !ok {
|
||||
return "unknown"
|
||||
}
|
||||
return name
|
||||
}
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
package evdev
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// EvType is EV_KEY, EV_SW, EV_LED, EV_SND, ...
|
||||
type EvType uint16
|
||||
|
||||
// EvCode describes codes within a type (eg. KEY_A, KEY_B, ...)
|
||||
type EvCode uint16
|
||||
|
||||
// EvProp describes device properties (eg. INPUT_PROP_ACCELEROMETER, INPUT_PROP_BUTTONPAD, ...)
|
||||
type EvProp uint16
|
||||
|
||||
// StateMap describes the current state of codes within a type, as booleans.
|
||||
type StateMap map[EvCode]bool
|
||||
|
||||
// InputEvent describes an event that is generated by an InputDevice
|
||||
type InputEvent struct {
|
||||
Time syscall.Timeval // time in seconds since epoch at which event occurred
|
||||
Type EvType // event type - one of ecodes.EV_*
|
||||
Code EvCode // event code related to the event type
|
||||
Value int32 // event value related to the event type
|
||||
}
|
||||
|
||||
func (e *InputEvent) TypeName() string {
|
||||
return TypeName(e.Type)
|
||||
}
|
||||
|
||||
func (e *InputEvent) CodeName() string {
|
||||
return CodeName(e.Type, e.Code)
|
||||
}
|
||||
|
||||
func (e *InputEvent) String() string {
|
||||
return fmt.Sprintf(
|
||||
"type: 0x%02x [%s], code: 0x%02x [%s], value: %d",
|
||||
e.Type, e.TypeName(), e.Code, e.CodeName(), e.Value,
|
||||
)
|
||||
}
|
||||
|
||||
// InputID ...
|
||||
type InputID struct {
|
||||
BusType uint16
|
||||
Vendor uint16
|
||||
Product uint16
|
||||
Version uint16
|
||||
}
|
||||
|
||||
// AbsInfo describes details on ABS input types
|
||||
type AbsInfo struct {
|
||||
Value int32
|
||||
Minimum int32
|
||||
Maximum int32
|
||||
Fuzz int32
|
||||
Flat int32
|
||||
Resolution int32
|
||||
}
|
||||
|
||||
// InputKeymapEntry is used to retrieve and modify keymap data
|
||||
type InputKeymapEntry struct {
|
||||
Flags uint8
|
||||
Len uint8
|
||||
Index uint16
|
||||
KeyCode uint32
|
||||
ScanCode [32]uint8
|
||||
}
|
||||
|
||||
// InputMask ...
|
||||
type InputMask struct {
|
||||
Type uint32
|
||||
CodesSize uint32
|
||||
CodesPtr uint64
|
||||
}
|
||||
|
||||
// UinputUserDevice is used when creating or cloning a device
|
||||
type UinputUserDevice struct {
|
||||
Name [uinputMaxNameSize]byte
|
||||
ID InputID
|
||||
EffectsMax uint32
|
||||
Absmax [absSize]int32
|
||||
Absmin [absSize]int32
|
||||
Absfuzz [absSize]int32
|
||||
Absflat [absSize]int32
|
||||
}
|
||||
+160
@@ -0,0 +1,160 @@
|
||||
package evdev
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"os"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
const (
|
||||
uinputMaxNameSize = 80
|
||||
absSize = 64
|
||||
)
|
||||
|
||||
// CreateDevice creates a device from scratch with the provided capabilities and name
|
||||
// If set up fails the device will be removed from the system,
|
||||
// once set up it can be removed by calling dev.Close
|
||||
func CreateDevice(name string, id InputID, capabilities map[EvType][]EvCode) (*InputDevice, error) {
|
||||
deviceFile, err := os.OpenFile("/dev/uinput", syscall.O_WRONLY|syscall.O_NONBLOCK, 0660)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
newDev := &InputDevice{
|
||||
file: deviceFile,
|
||||
}
|
||||
|
||||
for ev, codes := range capabilities {
|
||||
if err := ioctlUISETEVBIT(newDev.file.Fd(), uintptr(ev)); err != nil {
|
||||
DestroyDevice(newDev)
|
||||
return nil, fmt.Errorf("failed to set ev bit: %d - %w", ev, err)
|
||||
}
|
||||
|
||||
if err := setEventCodes(newDev, ev, codes); err != nil {
|
||||
DestroyDevice(newDev)
|
||||
return nil, fmt.Errorf("failed to set ev code: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if _, err = createInputDevice(newDev.file, UinputUserDevice{
|
||||
Name: toUinputName([]byte(name)),
|
||||
ID: id,
|
||||
}); err != nil {
|
||||
DestroyDevice(newDev)
|
||||
return nil, fmt.Errorf("failed to create device: %w", err)
|
||||
}
|
||||
|
||||
return newDev, nil
|
||||
}
|
||||
|
||||
// CloneDevice creates a new device from an existing one
|
||||
// all capabilites will be coppied over to the new virtual device
|
||||
// If set up fails the device will be removed from the system,
|
||||
// once set up it can be removed by calling dev.Close
|
||||
func CloneDevice(name string, dev *InputDevice) (*InputDevice, error) {
|
||||
deviceFile, err := os.OpenFile("/dev/uinput", syscall.O_WRONLY|syscall.O_NONBLOCK, 0660)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
newDev := &InputDevice{
|
||||
file: deviceFile,
|
||||
driverVersion: dev.driverVersion,
|
||||
}
|
||||
|
||||
for _, ev := range dev.CapableTypes() {
|
||||
if err := ioctlUISETEVBIT(newDev.file.Fd(), uintptr(ev)); err != nil {
|
||||
DestroyDevice(newDev)
|
||||
return nil, fmt.Errorf("failed to set ev bit: %d - %w", ev, err)
|
||||
}
|
||||
|
||||
eventCodes := dev.CapableEvents(ev)
|
||||
if err := setEventCodes(newDev, ev, eventCodes); err != nil {
|
||||
DestroyDevice(newDev)
|
||||
return nil, fmt.Errorf("failed to set ev code: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
id, err := dev.InputID()
|
||||
if err != nil {
|
||||
DestroyDevice(newDev)
|
||||
return nil, fmt.Errorf("failed to get original device id: %w", err)
|
||||
}
|
||||
|
||||
if _, err = createInputDevice(newDev.file, UinputUserDevice{
|
||||
Name: toUinputName([]byte(name)),
|
||||
ID: id,
|
||||
}); err != nil {
|
||||
return nil, fmt.Errorf("failed to create device: %w", err)
|
||||
}
|
||||
|
||||
return newDev, nil
|
||||
}
|
||||
|
||||
// Destroy destroys an input device, removing it from the system
|
||||
// This is designed to be called on self created virtual devices and may fail if called
|
||||
// on real devices attached to the system
|
||||
func DestroyDevice(dev *InputDevice) error {
|
||||
return ioctlUIDEVDESTROY(dev.file.Fd())
|
||||
}
|
||||
|
||||
func setEventCodes(dev *InputDevice, ev EvType, codes []EvCode) error {
|
||||
for _, code := range codes {
|
||||
var err error
|
||||
|
||||
switch ev {
|
||||
case EV_ABS:
|
||||
err = ioctlUISETABSBIT(dev.file.Fd(), uintptr(code))
|
||||
case EV_FF:
|
||||
err = ioctlUISETFFBIT(dev.file.Fd(), uintptr(code))
|
||||
case EV_KEY:
|
||||
err = ioctlUISETKEYBIT(dev.file.Fd(), uintptr(code))
|
||||
case EV_LED:
|
||||
err = ioctlUISETLEDBIT(dev.file.Fd(), uintptr(code))
|
||||
case EV_MSC:
|
||||
err = ioctlUISETMSCBIT(dev.file.Fd(), uintptr(code))
|
||||
case EV_REL:
|
||||
err = ioctlUISETRELBIT(dev.file.Fd(), uintptr(code))
|
||||
case EV_SND:
|
||||
err = ioctlUISETSNDBIT(dev.file.Fd(), uintptr(code))
|
||||
case EV_SW:
|
||||
err = ioctlUISETSWBIT(dev.file.Fd(), uintptr(code))
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func toUinputName(name []byte) (uinputName [uinputMaxNameSize]byte) {
|
||||
var fixedSizeName [uinputMaxNameSize]byte
|
||||
copy(fixedSizeName[:], name)
|
||||
|
||||
return fixedSizeName
|
||||
}
|
||||
|
||||
func createInputDevice(file *os.File, dev UinputUserDevice) (fd *os.File, err error) {
|
||||
buf := new(bytes.Buffer)
|
||||
|
||||
if err = binary.Write(buf, binary.LittleEndian, dev); err != nil {
|
||||
file.Close()
|
||||
return nil, fmt.Errorf("failed to write user device buffer: %w", err)
|
||||
}
|
||||
|
||||
if _, err = file.Write(buf.Bytes()); err != nil {
|
||||
file.Close()
|
||||
return nil, fmt.Errorf("failed to write uidev struct to device file: %w", err)
|
||||
}
|
||||
|
||||
if err = ioctlUIDEVCREATE(file.Fd()); err != nil {
|
||||
file.Close()
|
||||
return nil, fmt.Errorf("failed to create device: %w", err)
|
||||
}
|
||||
|
||||
return file, nil
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
# Binaries for programs and plugins
|
||||
*.exe
|
||||
*.exe~
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
|
||||
# Test binary, build with `go test -c`
|
||||
*.test
|
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
+1379
File diff suppressed because it is too large
Load Diff
+593
@@ -0,0 +1,593 @@
|
||||
package alarmclock
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/xml"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
const (
|
||||
_ServiceURN = "urn:schemas-upnp-org:service:AlarmClock:1"
|
||||
_EncodingSchema = "http://schemas.xmlsoap.org/soap/encoding/"
|
||||
_EnvelopeSchema = "http://schemas.xmlsoap.org/soap/envelope/"
|
||||
)
|
||||
|
||||
type Service struct {
|
||||
ControlEndpoint *url.URL
|
||||
EventEndpoint *url.URL
|
||||
}
|
||||
|
||||
func NewService(deviceUrl *url.URL) *Service {
|
||||
c, err := url.Parse(`/AlarmClock/Control`)
|
||||
if nil != err {
|
||||
panic(err)
|
||||
}
|
||||
e, err := url.Parse(`/AlarmClock/Event`)
|
||||
if nil != err {
|
||||
panic(err)
|
||||
}
|
||||
return &Service{
|
||||
ControlEndpoint: deviceUrl.ResolveReference(c),
|
||||
EventEndpoint: deviceUrl.ResolveReference(e),
|
||||
}
|
||||
}
|
||||
|
||||
type Envelope struct {
|
||||
XMLName xml.Name `xml:"s:Envelope"`
|
||||
Xmlns string `xml:"xmlns:s,attr"`
|
||||
EncodingStyle string `xml:"s:encodingStyle,attr"`
|
||||
Body Body `xml:"s:Body"`
|
||||
}
|
||||
type Body struct {
|
||||
XMLName xml.Name `xml:"s:Body"`
|
||||
SetFormat *SetFormatArgs `xml:"u:SetFormat,omitempty"`
|
||||
GetFormat *GetFormatArgs `xml:"u:GetFormat,omitempty"`
|
||||
SetTimeZone *SetTimeZoneArgs `xml:"u:SetTimeZone,omitempty"`
|
||||
GetTimeZone *GetTimeZoneArgs `xml:"u:GetTimeZone,omitempty"`
|
||||
GetTimeZoneAndRule *GetTimeZoneAndRuleArgs `xml:"u:GetTimeZoneAndRule,omitempty"`
|
||||
GetTimeZoneRule *GetTimeZoneRuleArgs `xml:"u:GetTimeZoneRule,omitempty"`
|
||||
SetTimeServer *SetTimeServerArgs `xml:"u:SetTimeServer,omitempty"`
|
||||
GetTimeServer *GetTimeServerArgs `xml:"u:GetTimeServer,omitempty"`
|
||||
SetTimeNow *SetTimeNowArgs `xml:"u:SetTimeNow,omitempty"`
|
||||
GetHouseholdTimeAtStamp *GetHouseholdTimeAtStampArgs `xml:"u:GetHouseholdTimeAtStamp,omitempty"`
|
||||
GetTimeNow *GetTimeNowArgs `xml:"u:GetTimeNow,omitempty"`
|
||||
CreateAlarm *CreateAlarmArgs `xml:"u:CreateAlarm,omitempty"`
|
||||
UpdateAlarm *UpdateAlarmArgs `xml:"u:UpdateAlarm,omitempty"`
|
||||
DestroyAlarm *DestroyAlarmArgs `xml:"u:DestroyAlarm,omitempty"`
|
||||
ListAlarms *ListAlarmsArgs `xml:"u:ListAlarms,omitempty"`
|
||||
SetDailyIndexRefreshTime *SetDailyIndexRefreshTimeArgs `xml:"u:SetDailyIndexRefreshTime,omitempty"`
|
||||
GetDailyIndexRefreshTime *GetDailyIndexRefreshTimeArgs `xml:"u:GetDailyIndexRefreshTime,omitempty"`
|
||||
}
|
||||
type EnvelopeResponse struct {
|
||||
XMLName xml.Name `xml:"Envelope"`
|
||||
Xmlns string `xml:"xmlns:s,attr"`
|
||||
EncodingStyle string `xml:"encodingStyle,attr"`
|
||||
Body BodyResponse `xml:"Body"`
|
||||
}
|
||||
type BodyResponse struct {
|
||||
XMLName xml.Name `xml:"Body"`
|
||||
SetFormat *SetFormatResponse `xml:"SetFormatResponse,omitempty"`
|
||||
GetFormat *GetFormatResponse `xml:"GetFormatResponse,omitempty"`
|
||||
SetTimeZone *SetTimeZoneResponse `xml:"SetTimeZoneResponse,omitempty"`
|
||||
GetTimeZone *GetTimeZoneResponse `xml:"GetTimeZoneResponse,omitempty"`
|
||||
GetTimeZoneAndRule *GetTimeZoneAndRuleResponse `xml:"GetTimeZoneAndRuleResponse,omitempty"`
|
||||
GetTimeZoneRule *GetTimeZoneRuleResponse `xml:"GetTimeZoneRuleResponse,omitempty"`
|
||||
SetTimeServer *SetTimeServerResponse `xml:"SetTimeServerResponse,omitempty"`
|
||||
GetTimeServer *GetTimeServerResponse `xml:"GetTimeServerResponse,omitempty"`
|
||||
SetTimeNow *SetTimeNowResponse `xml:"SetTimeNowResponse,omitempty"`
|
||||
GetHouseholdTimeAtStamp *GetHouseholdTimeAtStampResponse `xml:"GetHouseholdTimeAtStampResponse,omitempty"`
|
||||
GetTimeNow *GetTimeNowResponse `xml:"GetTimeNowResponse,omitempty"`
|
||||
CreateAlarm *CreateAlarmResponse `xml:"CreateAlarmResponse,omitempty"`
|
||||
UpdateAlarm *UpdateAlarmResponse `xml:"UpdateAlarmResponse,omitempty"`
|
||||
DestroyAlarm *DestroyAlarmResponse `xml:"DestroyAlarmResponse,omitempty"`
|
||||
ListAlarms *ListAlarmsResponse `xml:"ListAlarmsResponse,omitempty"`
|
||||
SetDailyIndexRefreshTime *SetDailyIndexRefreshTimeResponse `xml:"SetDailyIndexRefreshTimeResponse,omitempty"`
|
||||
GetDailyIndexRefreshTime *GetDailyIndexRefreshTimeResponse `xml:"GetDailyIndexRefreshTimeResponse,omitempty"`
|
||||
}
|
||||
|
||||
func (s *Service) exec(actionName string, httpClient *http.Client, envelope *Envelope) (*EnvelopeResponse, error) {
|
||||
marshaled, err := xml.Marshal(envelope)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
postBody := []byte(`<?xml version="1.0"?>`)
|
||||
postBody = append(postBody, marshaled...)
|
||||
req, err := http.NewRequest(`POST`, s.ControlEndpoint.String(), bytes.NewBuffer(postBody))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set(`Content-Type`, `text/xml; charset="utf-8"`)
|
||||
req.Header.Set(`SOAPAction`, _ServiceURN+`#`+actionName)
|
||||
res, err := httpClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
responseBody, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var envelopeResponse EnvelopeResponse
|
||||
err = xml.Unmarshal(responseBody, &envelopeResponse)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &envelopeResponse, nil
|
||||
}
|
||||
|
||||
type SetFormatArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
DesiredTimeFormat string `xml:"DesiredTimeFormat"`
|
||||
DesiredDateFormat string `xml:"DesiredDateFormat"`
|
||||
}
|
||||
type SetFormatResponse struct {
|
||||
}
|
||||
|
||||
func (s *Service) SetFormat(httpClient *http.Client, args *SetFormatArgs) (*SetFormatResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`SetFormat`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{SetFormat: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.SetFormat == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling alarmclock.SetFormat()`)
|
||||
}
|
||||
|
||||
return r.Body.SetFormat, nil
|
||||
}
|
||||
|
||||
type GetFormatArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
}
|
||||
type GetFormatResponse struct {
|
||||
CurrentTimeFormat string `xml:"CurrentTimeFormat"`
|
||||
CurrentDateFormat string `xml:"CurrentDateFormat"`
|
||||
}
|
||||
|
||||
func (s *Service) GetFormat(httpClient *http.Client, args *GetFormatArgs) (*GetFormatResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`GetFormat`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{GetFormat: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.GetFormat == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling alarmclock.GetFormat()`)
|
||||
}
|
||||
|
||||
return r.Body.GetFormat, nil
|
||||
}
|
||||
|
||||
type SetTimeZoneArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
Index int32 `xml:"Index"`
|
||||
AutoAdjustDst bool `xml:"AutoAdjustDst"`
|
||||
}
|
||||
type SetTimeZoneResponse struct {
|
||||
}
|
||||
|
||||
func (s *Service) SetTimeZone(httpClient *http.Client, args *SetTimeZoneArgs) (*SetTimeZoneResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`SetTimeZone`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{SetTimeZone: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.SetTimeZone == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling alarmclock.SetTimeZone()`)
|
||||
}
|
||||
|
||||
return r.Body.SetTimeZone, nil
|
||||
}
|
||||
|
||||
type GetTimeZoneArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
}
|
||||
type GetTimeZoneResponse struct {
|
||||
Index int32 `xml:"Index"`
|
||||
AutoAdjustDst bool `xml:"AutoAdjustDst"`
|
||||
}
|
||||
|
||||
func (s *Service) GetTimeZone(httpClient *http.Client, args *GetTimeZoneArgs) (*GetTimeZoneResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`GetTimeZone`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{GetTimeZone: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.GetTimeZone == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling alarmclock.GetTimeZone()`)
|
||||
}
|
||||
|
||||
return r.Body.GetTimeZone, nil
|
||||
}
|
||||
|
||||
type GetTimeZoneAndRuleArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
}
|
||||
type GetTimeZoneAndRuleResponse struct {
|
||||
Index int32 `xml:"Index"`
|
||||
AutoAdjustDst bool `xml:"AutoAdjustDst"`
|
||||
CurrentTimeZone string `xml:"CurrentTimeZone"`
|
||||
}
|
||||
|
||||
func (s *Service) GetTimeZoneAndRule(httpClient *http.Client, args *GetTimeZoneAndRuleArgs) (*GetTimeZoneAndRuleResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`GetTimeZoneAndRule`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{GetTimeZoneAndRule: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.GetTimeZoneAndRule == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling alarmclock.GetTimeZoneAndRule()`)
|
||||
}
|
||||
|
||||
return r.Body.GetTimeZoneAndRule, nil
|
||||
}
|
||||
|
||||
type GetTimeZoneRuleArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
Index int32 `xml:"Index"`
|
||||
}
|
||||
type GetTimeZoneRuleResponse struct {
|
||||
TimeZone string `xml:"TimeZone"`
|
||||
}
|
||||
|
||||
func (s *Service) GetTimeZoneRule(httpClient *http.Client, args *GetTimeZoneRuleArgs) (*GetTimeZoneRuleResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`GetTimeZoneRule`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{GetTimeZoneRule: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.GetTimeZoneRule == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling alarmclock.GetTimeZoneRule()`)
|
||||
}
|
||||
|
||||
return r.Body.GetTimeZoneRule, nil
|
||||
}
|
||||
|
||||
type SetTimeServerArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
DesiredTimeServer string `xml:"DesiredTimeServer"`
|
||||
}
|
||||
type SetTimeServerResponse struct {
|
||||
}
|
||||
|
||||
func (s *Service) SetTimeServer(httpClient *http.Client, args *SetTimeServerArgs) (*SetTimeServerResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`SetTimeServer`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{SetTimeServer: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.SetTimeServer == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling alarmclock.SetTimeServer()`)
|
||||
}
|
||||
|
||||
return r.Body.SetTimeServer, nil
|
||||
}
|
||||
|
||||
type GetTimeServerArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
}
|
||||
type GetTimeServerResponse struct {
|
||||
CurrentTimeServer string `xml:"CurrentTimeServer"`
|
||||
}
|
||||
|
||||
func (s *Service) GetTimeServer(httpClient *http.Client, args *GetTimeServerArgs) (*GetTimeServerResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`GetTimeServer`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{GetTimeServer: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.GetTimeServer == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling alarmclock.GetTimeServer()`)
|
||||
}
|
||||
|
||||
return r.Body.GetTimeServer, nil
|
||||
}
|
||||
|
||||
type SetTimeNowArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
DesiredTime string `xml:"DesiredTime"`
|
||||
TimeZoneForDesiredTime string `xml:"TimeZoneForDesiredTime"`
|
||||
}
|
||||
type SetTimeNowResponse struct {
|
||||
}
|
||||
|
||||
func (s *Service) SetTimeNow(httpClient *http.Client, args *SetTimeNowArgs) (*SetTimeNowResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`SetTimeNow`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{SetTimeNow: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.SetTimeNow == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling alarmclock.SetTimeNow()`)
|
||||
}
|
||||
|
||||
return r.Body.SetTimeNow, nil
|
||||
}
|
||||
|
||||
type GetHouseholdTimeAtStampArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
TimeStamp string `xml:"TimeStamp"`
|
||||
}
|
||||
type GetHouseholdTimeAtStampResponse struct {
|
||||
HouseholdUTCTime string `xml:"HouseholdUTCTime"`
|
||||
}
|
||||
|
||||
func (s *Service) GetHouseholdTimeAtStamp(httpClient *http.Client, args *GetHouseholdTimeAtStampArgs) (*GetHouseholdTimeAtStampResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`GetHouseholdTimeAtStamp`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{GetHouseholdTimeAtStamp: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.GetHouseholdTimeAtStamp == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling alarmclock.GetHouseholdTimeAtStamp()`)
|
||||
}
|
||||
|
||||
return r.Body.GetHouseholdTimeAtStamp, nil
|
||||
}
|
||||
|
||||
type GetTimeNowArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
}
|
||||
type GetTimeNowResponse struct {
|
||||
CurrentUTCTime string `xml:"CurrentUTCTime"`
|
||||
CurrentLocalTime string `xml:"CurrentLocalTime"`
|
||||
CurrentTimeZone string `xml:"CurrentTimeZone"`
|
||||
CurrentTimeGeneration uint32 `xml:"CurrentTimeGeneration"`
|
||||
}
|
||||
|
||||
func (s *Service) GetTimeNow(httpClient *http.Client, args *GetTimeNowArgs) (*GetTimeNowResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`GetTimeNow`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{GetTimeNow: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.GetTimeNow == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling alarmclock.GetTimeNow()`)
|
||||
}
|
||||
|
||||
return r.Body.GetTimeNow, nil
|
||||
}
|
||||
|
||||
type CreateAlarmArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
StartLocalTime string `xml:"StartLocalTime"`
|
||||
Duration string `xml:"Duration"`
|
||||
// Allowed Value: ONCE
|
||||
// Allowed Value: WEEKDAYS
|
||||
// Allowed Value: WEEKENDS
|
||||
// Allowed Value: DAILY
|
||||
Recurrence string `xml:"Recurrence"`
|
||||
Enabled bool `xml:"Enabled"`
|
||||
RoomUUID string `xml:"RoomUUID"`
|
||||
ProgramURI string `xml:"ProgramURI"`
|
||||
ProgramMetaData string `xml:"ProgramMetaData"`
|
||||
// Allowed Value: NORMAL
|
||||
// Allowed Value: REPEAT_ALL
|
||||
// Allowed Value: SHUFFLE_NOREPEAT
|
||||
// Allowed Value: SHUFFLE
|
||||
PlayMode string `xml:"PlayMode"`
|
||||
Volume uint16 `xml:"Volume"`
|
||||
IncludeLinkedZones bool `xml:"IncludeLinkedZones"`
|
||||
}
|
||||
type CreateAlarmResponse struct {
|
||||
AssignedID uint32 `xml:"AssignedID"`
|
||||
}
|
||||
|
||||
func (s *Service) CreateAlarm(httpClient *http.Client, args *CreateAlarmArgs) (*CreateAlarmResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`CreateAlarm`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{CreateAlarm: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.CreateAlarm == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling alarmclock.CreateAlarm()`)
|
||||
}
|
||||
|
||||
return r.Body.CreateAlarm, nil
|
||||
}
|
||||
|
||||
type UpdateAlarmArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
ID uint32 `xml:"ID"`
|
||||
StartLocalTime string `xml:"StartLocalTime"`
|
||||
Duration string `xml:"Duration"`
|
||||
// Allowed Value: ONCE
|
||||
// Allowed Value: WEEKDAYS
|
||||
// Allowed Value: WEEKENDS
|
||||
// Allowed Value: DAILY
|
||||
Recurrence string `xml:"Recurrence"`
|
||||
Enabled bool `xml:"Enabled"`
|
||||
RoomUUID string `xml:"RoomUUID"`
|
||||
ProgramURI string `xml:"ProgramURI"`
|
||||
ProgramMetaData string `xml:"ProgramMetaData"`
|
||||
// Allowed Value: NORMAL
|
||||
// Allowed Value: REPEAT_ALL
|
||||
// Allowed Value: SHUFFLE_NOREPEAT
|
||||
// Allowed Value: SHUFFLE
|
||||
PlayMode string `xml:"PlayMode"`
|
||||
Volume uint16 `xml:"Volume"`
|
||||
IncludeLinkedZones bool `xml:"IncludeLinkedZones"`
|
||||
}
|
||||
type UpdateAlarmResponse struct {
|
||||
}
|
||||
|
||||
func (s *Service) UpdateAlarm(httpClient *http.Client, args *UpdateAlarmArgs) (*UpdateAlarmResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`UpdateAlarm`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{UpdateAlarm: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.UpdateAlarm == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling alarmclock.UpdateAlarm()`)
|
||||
}
|
||||
|
||||
return r.Body.UpdateAlarm, nil
|
||||
}
|
||||
|
||||
type DestroyAlarmArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
ID uint32 `xml:"ID"`
|
||||
}
|
||||
type DestroyAlarmResponse struct {
|
||||
}
|
||||
|
||||
func (s *Service) DestroyAlarm(httpClient *http.Client, args *DestroyAlarmArgs) (*DestroyAlarmResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`DestroyAlarm`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{DestroyAlarm: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.DestroyAlarm == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling alarmclock.DestroyAlarm()`)
|
||||
}
|
||||
|
||||
return r.Body.DestroyAlarm, nil
|
||||
}
|
||||
|
||||
type ListAlarmsArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
}
|
||||
type ListAlarmsResponse struct {
|
||||
CurrentAlarmList string `xml:"CurrentAlarmList"`
|
||||
CurrentAlarmListVersion string `xml:"CurrentAlarmListVersion"`
|
||||
}
|
||||
|
||||
func (s *Service) ListAlarms(httpClient *http.Client, args *ListAlarmsArgs) (*ListAlarmsResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`ListAlarms`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{ListAlarms: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.ListAlarms == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling alarmclock.ListAlarms()`)
|
||||
}
|
||||
|
||||
return r.Body.ListAlarms, nil
|
||||
}
|
||||
|
||||
type SetDailyIndexRefreshTimeArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
DesiredDailyIndexRefreshTime string `xml:"DesiredDailyIndexRefreshTime"`
|
||||
}
|
||||
type SetDailyIndexRefreshTimeResponse struct {
|
||||
}
|
||||
|
||||
func (s *Service) SetDailyIndexRefreshTime(httpClient *http.Client, args *SetDailyIndexRefreshTimeArgs) (*SetDailyIndexRefreshTimeResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`SetDailyIndexRefreshTime`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{SetDailyIndexRefreshTime: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.SetDailyIndexRefreshTime == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling alarmclock.SetDailyIndexRefreshTime()`)
|
||||
}
|
||||
|
||||
return r.Body.SetDailyIndexRefreshTime, nil
|
||||
}
|
||||
|
||||
type GetDailyIndexRefreshTimeArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
}
|
||||
type GetDailyIndexRefreshTimeResponse struct {
|
||||
CurrentDailyIndexRefreshTime string `xml:"CurrentDailyIndexRefreshTime"`
|
||||
}
|
||||
|
||||
func (s *Service) GetDailyIndexRefreshTime(httpClient *http.Client, args *GetDailyIndexRefreshTimeArgs) (*GetDailyIndexRefreshTimeResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`GetDailyIndexRefreshTime`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{GetDailyIndexRefreshTime: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.GetDailyIndexRefreshTime == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling alarmclock.GetDailyIndexRefreshTime()`)
|
||||
}
|
||||
|
||||
return r.Body.GetDailyIndexRefreshTime, nil
|
||||
}
|
||||
+174
@@ -0,0 +1,174 @@
|
||||
package connectionmanager
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/xml"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
const (
|
||||
_ServiceURN = "urn:schemas-upnp-org:service:ConnectionManager:1"
|
||||
_EncodingSchema = "http://schemas.xmlsoap.org/soap/encoding/"
|
||||
_EnvelopeSchema = "http://schemas.xmlsoap.org/soap/envelope/"
|
||||
)
|
||||
|
||||
type Service struct {
|
||||
ControlEndpoint *url.URL
|
||||
EventEndpoint *url.URL
|
||||
}
|
||||
|
||||
func NewService(deviceUrl *url.URL) *Service {
|
||||
c, err := url.Parse(`/MediaServer/ConnectionManager/Control`)
|
||||
if nil != err {
|
||||
panic(err)
|
||||
}
|
||||
e, err := url.Parse(`/MediaServer/ConnectionManager/Event`)
|
||||
if nil != err {
|
||||
panic(err)
|
||||
}
|
||||
return &Service{
|
||||
ControlEndpoint: deviceUrl.ResolveReference(c),
|
||||
EventEndpoint: deviceUrl.ResolveReference(e),
|
||||
}
|
||||
}
|
||||
|
||||
type Envelope struct {
|
||||
XMLName xml.Name `xml:"s:Envelope"`
|
||||
Xmlns string `xml:"xmlns:s,attr"`
|
||||
EncodingStyle string `xml:"s:encodingStyle,attr"`
|
||||
Body Body `xml:"s:Body"`
|
||||
}
|
||||
type Body struct {
|
||||
XMLName xml.Name `xml:"s:Body"`
|
||||
GetProtocolInfo *GetProtocolInfoArgs `xml:"u:GetProtocolInfo,omitempty"`
|
||||
GetCurrentConnectionIDs *GetCurrentConnectionIDsArgs `xml:"u:GetCurrentConnectionIDs,omitempty"`
|
||||
GetCurrentConnectionInfo *GetCurrentConnectionInfoArgs `xml:"u:GetCurrentConnectionInfo,omitempty"`
|
||||
}
|
||||
type EnvelopeResponse struct {
|
||||
XMLName xml.Name `xml:"Envelope"`
|
||||
Xmlns string `xml:"xmlns:s,attr"`
|
||||
EncodingStyle string `xml:"encodingStyle,attr"`
|
||||
Body BodyResponse `xml:"Body"`
|
||||
}
|
||||
type BodyResponse struct {
|
||||
XMLName xml.Name `xml:"Body"`
|
||||
GetProtocolInfo *GetProtocolInfoResponse `xml:"GetProtocolInfoResponse,omitempty"`
|
||||
GetCurrentConnectionIDs *GetCurrentConnectionIDsResponse `xml:"GetCurrentConnectionIDsResponse,omitempty"`
|
||||
GetCurrentConnectionInfo *GetCurrentConnectionInfoResponse `xml:"GetCurrentConnectionInfoResponse,omitempty"`
|
||||
}
|
||||
|
||||
func (s *Service) exec(actionName string, httpClient *http.Client, envelope *Envelope) (*EnvelopeResponse, error) {
|
||||
marshaled, err := xml.Marshal(envelope)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
postBody := []byte(`<?xml version="1.0"?>`)
|
||||
postBody = append(postBody, marshaled...)
|
||||
req, err := http.NewRequest(`POST`, s.ControlEndpoint.String(), bytes.NewBuffer(postBody))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set(`Content-Type`, `text/xml; charset="utf-8"`)
|
||||
req.Header.Set(`SOAPAction`, _ServiceURN+`#`+actionName)
|
||||
res, err := httpClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
responseBody, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var envelopeResponse EnvelopeResponse
|
||||
err = xml.Unmarshal(responseBody, &envelopeResponse)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &envelopeResponse, nil
|
||||
}
|
||||
|
||||
type GetProtocolInfoArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
}
|
||||
type GetProtocolInfoResponse struct {
|
||||
Source string `xml:"Source"`
|
||||
Sink string `xml:"Sink"`
|
||||
}
|
||||
|
||||
func (s *Service) GetProtocolInfo(httpClient *http.Client, args *GetProtocolInfoArgs) (*GetProtocolInfoResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`GetProtocolInfo`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{GetProtocolInfo: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.GetProtocolInfo == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling connectionmanager.GetProtocolInfo()`)
|
||||
}
|
||||
|
||||
return r.Body.GetProtocolInfo, nil
|
||||
}
|
||||
|
||||
type GetCurrentConnectionIDsArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
}
|
||||
type GetCurrentConnectionIDsResponse struct {
|
||||
ConnectionIDs string `xml:"ConnectionIDs"`
|
||||
}
|
||||
|
||||
func (s *Service) GetCurrentConnectionIDs(httpClient *http.Client, args *GetCurrentConnectionIDsArgs) (*GetCurrentConnectionIDsResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`GetCurrentConnectionIDs`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{GetCurrentConnectionIDs: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.GetCurrentConnectionIDs == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling connectionmanager.GetCurrentConnectionIDs()`)
|
||||
}
|
||||
|
||||
return r.Body.GetCurrentConnectionIDs, nil
|
||||
}
|
||||
|
||||
type GetCurrentConnectionInfoArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
ConnectionID int32 `xml:"ConnectionID"`
|
||||
}
|
||||
type GetCurrentConnectionInfoResponse struct {
|
||||
RcsID int32 `xml:"RcsID"`
|
||||
AVTransportID int32 `xml:"AVTransportID"`
|
||||
ProtocolInfo string `xml:"ProtocolInfo"`
|
||||
PeerConnectionManager string `xml:"PeerConnectionManager"`
|
||||
PeerConnectionID int32 `xml:"PeerConnectionID"`
|
||||
Direction string `xml:"Direction"`
|
||||
Status string `xml:"Status"`
|
||||
}
|
||||
|
||||
func (s *Service) GetCurrentConnectionInfo(httpClient *http.Client, args *GetCurrentConnectionInfoArgs) (*GetCurrentConnectionInfoResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`GetCurrentConnectionInfo`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{GetCurrentConnectionInfo: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.GetCurrentConnectionInfo == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling connectionmanager.GetCurrentConnectionInfo()`)
|
||||
}
|
||||
|
||||
return r.Body.GetCurrentConnectionInfo, nil
|
||||
}
|
||||
+539
@@ -0,0 +1,539 @@
|
||||
package contentdirectory
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/xml"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
const (
|
||||
_ServiceURN = "urn:schemas-upnp-org:service:ContentDirectory:1"
|
||||
_EncodingSchema = "http://schemas.xmlsoap.org/soap/encoding/"
|
||||
_EnvelopeSchema = "http://schemas.xmlsoap.org/soap/envelope/"
|
||||
)
|
||||
|
||||
type Service struct {
|
||||
ControlEndpoint *url.URL
|
||||
EventEndpoint *url.URL
|
||||
}
|
||||
|
||||
func NewService(deviceUrl *url.URL) *Service {
|
||||
c, err := url.Parse(`/MediaServer/ContentDirectory/Control`)
|
||||
if nil != err {
|
||||
panic(err)
|
||||
}
|
||||
e, err := url.Parse(`/MediaServer/ContentDirectory/Event`)
|
||||
if nil != err {
|
||||
panic(err)
|
||||
}
|
||||
return &Service{
|
||||
ControlEndpoint: deviceUrl.ResolveReference(c),
|
||||
EventEndpoint: deviceUrl.ResolveReference(e),
|
||||
}
|
||||
}
|
||||
|
||||
type Envelope struct {
|
||||
XMLName xml.Name `xml:"s:Envelope"`
|
||||
Xmlns string `xml:"xmlns:s,attr"`
|
||||
EncodingStyle string `xml:"s:encodingStyle,attr"`
|
||||
Body Body `xml:"s:Body"`
|
||||
}
|
||||
type Body struct {
|
||||
XMLName xml.Name `xml:"s:Body"`
|
||||
GetSearchCapabilities *GetSearchCapabilitiesArgs `xml:"u:GetSearchCapabilities,omitempty"`
|
||||
GetSortCapabilities *GetSortCapabilitiesArgs `xml:"u:GetSortCapabilities,omitempty"`
|
||||
GetSystemUpdateID *GetSystemUpdateIDArgs `xml:"u:GetSystemUpdateID,omitempty"`
|
||||
GetAlbumArtistDisplayOption *GetAlbumArtistDisplayOptionArgs `xml:"u:GetAlbumArtistDisplayOption,omitempty"`
|
||||
GetLastIndexChange *GetLastIndexChangeArgs `xml:"u:GetLastIndexChange,omitempty"`
|
||||
Browse *BrowseArgs `xml:"u:Browse,omitempty"`
|
||||
FindPrefix *FindPrefixArgs `xml:"u:FindPrefix,omitempty"`
|
||||
GetAllPrefixLocations *GetAllPrefixLocationsArgs `xml:"u:GetAllPrefixLocations,omitempty"`
|
||||
CreateObject *CreateObjectArgs `xml:"u:CreateObject,omitempty"`
|
||||
UpdateObject *UpdateObjectArgs `xml:"u:UpdateObject,omitempty"`
|
||||
DestroyObject *DestroyObjectArgs `xml:"u:DestroyObject,omitempty"`
|
||||
RefreshShareIndex *RefreshShareIndexArgs `xml:"u:RefreshShareIndex,omitempty"`
|
||||
RequestResort *RequestResortArgs `xml:"u:RequestResort,omitempty"`
|
||||
GetShareIndexInProgress *GetShareIndexInProgressArgs `xml:"u:GetShareIndexInProgress,omitempty"`
|
||||
GetBrowseable *GetBrowseableArgs `xml:"u:GetBrowseable,omitempty"`
|
||||
SetBrowseable *SetBrowseableArgs `xml:"u:SetBrowseable,omitempty"`
|
||||
}
|
||||
type EnvelopeResponse struct {
|
||||
XMLName xml.Name `xml:"Envelope"`
|
||||
Xmlns string `xml:"xmlns:s,attr"`
|
||||
EncodingStyle string `xml:"encodingStyle,attr"`
|
||||
Body BodyResponse `xml:"Body"`
|
||||
}
|
||||
type BodyResponse struct {
|
||||
XMLName xml.Name `xml:"Body"`
|
||||
GetSearchCapabilities *GetSearchCapabilitiesResponse `xml:"GetSearchCapabilitiesResponse,omitempty"`
|
||||
GetSortCapabilities *GetSortCapabilitiesResponse `xml:"GetSortCapabilitiesResponse,omitempty"`
|
||||
GetSystemUpdateID *GetSystemUpdateIDResponse `xml:"GetSystemUpdateIDResponse,omitempty"`
|
||||
GetAlbumArtistDisplayOption *GetAlbumArtistDisplayOptionResponse `xml:"GetAlbumArtistDisplayOptionResponse,omitempty"`
|
||||
GetLastIndexChange *GetLastIndexChangeResponse `xml:"GetLastIndexChangeResponse,omitempty"`
|
||||
Browse *BrowseResponse `xml:"BrowseResponse,omitempty"`
|
||||
FindPrefix *FindPrefixResponse `xml:"FindPrefixResponse,omitempty"`
|
||||
GetAllPrefixLocations *GetAllPrefixLocationsResponse `xml:"GetAllPrefixLocationsResponse,omitempty"`
|
||||
CreateObject *CreateObjectResponse `xml:"CreateObjectResponse,omitempty"`
|
||||
UpdateObject *UpdateObjectResponse `xml:"UpdateObjectResponse,omitempty"`
|
||||
DestroyObject *DestroyObjectResponse `xml:"DestroyObjectResponse,omitempty"`
|
||||
RefreshShareIndex *RefreshShareIndexResponse `xml:"RefreshShareIndexResponse,omitempty"`
|
||||
RequestResort *RequestResortResponse `xml:"RequestResortResponse,omitempty"`
|
||||
GetShareIndexInProgress *GetShareIndexInProgressResponse `xml:"GetShareIndexInProgressResponse,omitempty"`
|
||||
GetBrowseable *GetBrowseableResponse `xml:"GetBrowseableResponse,omitempty"`
|
||||
SetBrowseable *SetBrowseableResponse `xml:"SetBrowseableResponse,omitempty"`
|
||||
}
|
||||
|
||||
func (s *Service) exec(actionName string, httpClient *http.Client, envelope *Envelope) (*EnvelopeResponse, error) {
|
||||
marshaled, err := xml.Marshal(envelope)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
postBody := []byte(`<?xml version="1.0"?>`)
|
||||
postBody = append(postBody, marshaled...)
|
||||
req, err := http.NewRequest(`POST`, s.ControlEndpoint.String(), bytes.NewBuffer(postBody))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set(`Content-Type`, `text/xml; charset="utf-8"`)
|
||||
req.Header.Set(`SOAPAction`, _ServiceURN+`#`+actionName)
|
||||
res, err := httpClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
responseBody, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var envelopeResponse EnvelopeResponse
|
||||
err = xml.Unmarshal(responseBody, &envelopeResponse)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &envelopeResponse, nil
|
||||
}
|
||||
|
||||
type GetSearchCapabilitiesArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
}
|
||||
type GetSearchCapabilitiesResponse struct {
|
||||
SearchCaps string `xml:"SearchCaps"`
|
||||
}
|
||||
|
||||
func (s *Service) GetSearchCapabilities(httpClient *http.Client, args *GetSearchCapabilitiesArgs) (*GetSearchCapabilitiesResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`GetSearchCapabilities`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{GetSearchCapabilities: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.GetSearchCapabilities == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling contentdirectory.GetSearchCapabilities()`)
|
||||
}
|
||||
|
||||
return r.Body.GetSearchCapabilities, nil
|
||||
}
|
||||
|
||||
type GetSortCapabilitiesArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
}
|
||||
type GetSortCapabilitiesResponse struct {
|
||||
SortCaps string `xml:"SortCaps"`
|
||||
}
|
||||
|
||||
func (s *Service) GetSortCapabilities(httpClient *http.Client, args *GetSortCapabilitiesArgs) (*GetSortCapabilitiesResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`GetSortCapabilities`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{GetSortCapabilities: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.GetSortCapabilities == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling contentdirectory.GetSortCapabilities()`)
|
||||
}
|
||||
|
||||
return r.Body.GetSortCapabilities, nil
|
||||
}
|
||||
|
||||
type GetSystemUpdateIDArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
}
|
||||
type GetSystemUpdateIDResponse struct {
|
||||
Id uint32 `xml:"Id"`
|
||||
}
|
||||
|
||||
func (s *Service) GetSystemUpdateID(httpClient *http.Client, args *GetSystemUpdateIDArgs) (*GetSystemUpdateIDResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`GetSystemUpdateID`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{GetSystemUpdateID: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.GetSystemUpdateID == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling contentdirectory.GetSystemUpdateID()`)
|
||||
}
|
||||
|
||||
return r.Body.GetSystemUpdateID, nil
|
||||
}
|
||||
|
||||
type GetAlbumArtistDisplayOptionArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
}
|
||||
type GetAlbumArtistDisplayOptionResponse struct {
|
||||
AlbumArtistDisplayOption string `xml:"AlbumArtistDisplayOption"`
|
||||
}
|
||||
|
||||
func (s *Service) GetAlbumArtistDisplayOption(httpClient *http.Client, args *GetAlbumArtistDisplayOptionArgs) (*GetAlbumArtistDisplayOptionResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`GetAlbumArtistDisplayOption`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{GetAlbumArtistDisplayOption: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.GetAlbumArtistDisplayOption == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling contentdirectory.GetAlbumArtistDisplayOption()`)
|
||||
}
|
||||
|
||||
return r.Body.GetAlbumArtistDisplayOption, nil
|
||||
}
|
||||
|
||||
type GetLastIndexChangeArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
}
|
||||
type GetLastIndexChangeResponse struct {
|
||||
LastIndexChange string `xml:"LastIndexChange"`
|
||||
}
|
||||
|
||||
func (s *Service) GetLastIndexChange(httpClient *http.Client, args *GetLastIndexChangeArgs) (*GetLastIndexChangeResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`GetLastIndexChange`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{GetLastIndexChange: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.GetLastIndexChange == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling contentdirectory.GetLastIndexChange()`)
|
||||
}
|
||||
|
||||
return r.Body.GetLastIndexChange, nil
|
||||
}
|
||||
|
||||
type BrowseArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
ObjectID string `xml:"ObjectID"`
|
||||
// Allowed Value: BrowseMetadata
|
||||
// Allowed Value: BrowseDirectChildren
|
||||
BrowseFlag string `xml:"BrowseFlag"`
|
||||
Filter string `xml:"Filter"`
|
||||
StartingIndex uint32 `xml:"StartingIndex"`
|
||||
RequestedCount uint32 `xml:"RequestedCount"`
|
||||
SortCriteria string `xml:"SortCriteria"`
|
||||
}
|
||||
type BrowseResponse struct {
|
||||
Result string `xml:"Result"`
|
||||
NumberReturned uint32 `xml:"NumberReturned"`
|
||||
TotalMatches uint32 `xml:"TotalMatches"`
|
||||
UpdateID uint32 `xml:"UpdateID"`
|
||||
}
|
||||
|
||||
func (s *Service) Browse(httpClient *http.Client, args *BrowseArgs) (*BrowseResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`Browse`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{Browse: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.Browse == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling contentdirectory.Browse()`)
|
||||
}
|
||||
|
||||
return r.Body.Browse, nil
|
||||
}
|
||||
|
||||
type FindPrefixArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
ObjectID string `xml:"ObjectID"`
|
||||
Prefix string `xml:"Prefix"`
|
||||
}
|
||||
type FindPrefixResponse struct {
|
||||
StartingIndex uint32 `xml:"StartingIndex"`
|
||||
UpdateID uint32 `xml:"UpdateID"`
|
||||
}
|
||||
|
||||
func (s *Service) FindPrefix(httpClient *http.Client, args *FindPrefixArgs) (*FindPrefixResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`FindPrefix`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{FindPrefix: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.FindPrefix == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling contentdirectory.FindPrefix()`)
|
||||
}
|
||||
|
||||
return r.Body.FindPrefix, nil
|
||||
}
|
||||
|
||||
type GetAllPrefixLocationsArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
ObjectID string `xml:"ObjectID"`
|
||||
}
|
||||
type GetAllPrefixLocationsResponse struct {
|
||||
TotalPrefixes uint32 `xml:"TotalPrefixes"`
|
||||
PrefixAndIndexCSV string `xml:"PrefixAndIndexCSV"`
|
||||
UpdateID uint32 `xml:"UpdateID"`
|
||||
}
|
||||
|
||||
func (s *Service) GetAllPrefixLocations(httpClient *http.Client, args *GetAllPrefixLocationsArgs) (*GetAllPrefixLocationsResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`GetAllPrefixLocations`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{GetAllPrefixLocations: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.GetAllPrefixLocations == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling contentdirectory.GetAllPrefixLocations()`)
|
||||
}
|
||||
|
||||
return r.Body.GetAllPrefixLocations, nil
|
||||
}
|
||||
|
||||
type CreateObjectArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
ContainerID string `xml:"ContainerID"`
|
||||
Elements string `xml:"Elements"`
|
||||
}
|
||||
type CreateObjectResponse struct {
|
||||
ObjectID string `xml:"ObjectID"`
|
||||
Result string `xml:"Result"`
|
||||
}
|
||||
|
||||
func (s *Service) CreateObject(httpClient *http.Client, args *CreateObjectArgs) (*CreateObjectResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`CreateObject`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{CreateObject: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.CreateObject == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling contentdirectory.CreateObject()`)
|
||||
}
|
||||
|
||||
return r.Body.CreateObject, nil
|
||||
}
|
||||
|
||||
type UpdateObjectArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
ObjectID string `xml:"ObjectID"`
|
||||
CurrentTagValue string `xml:"CurrentTagValue"`
|
||||
NewTagValue string `xml:"NewTagValue"`
|
||||
}
|
||||
type UpdateObjectResponse struct {
|
||||
}
|
||||
|
||||
func (s *Service) UpdateObject(httpClient *http.Client, args *UpdateObjectArgs) (*UpdateObjectResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`UpdateObject`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{UpdateObject: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.UpdateObject == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling contentdirectory.UpdateObject()`)
|
||||
}
|
||||
|
||||
return r.Body.UpdateObject, nil
|
||||
}
|
||||
|
||||
type DestroyObjectArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
ObjectID string `xml:"ObjectID"`
|
||||
}
|
||||
type DestroyObjectResponse struct {
|
||||
}
|
||||
|
||||
func (s *Service) DestroyObject(httpClient *http.Client, args *DestroyObjectArgs) (*DestroyObjectResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`DestroyObject`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{DestroyObject: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.DestroyObject == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling contentdirectory.DestroyObject()`)
|
||||
}
|
||||
|
||||
return r.Body.DestroyObject, nil
|
||||
}
|
||||
|
||||
type RefreshShareIndexArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
AlbumArtistDisplayOption string `xml:"AlbumArtistDisplayOption"`
|
||||
}
|
||||
type RefreshShareIndexResponse struct {
|
||||
}
|
||||
|
||||
func (s *Service) RefreshShareIndex(httpClient *http.Client, args *RefreshShareIndexArgs) (*RefreshShareIndexResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`RefreshShareIndex`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{RefreshShareIndex: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.RefreshShareIndex == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling contentdirectory.RefreshShareIndex()`)
|
||||
}
|
||||
|
||||
return r.Body.RefreshShareIndex, nil
|
||||
}
|
||||
|
||||
type RequestResortArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
SortOrder string `xml:"SortOrder"`
|
||||
}
|
||||
type RequestResortResponse struct {
|
||||
}
|
||||
|
||||
func (s *Service) RequestResort(httpClient *http.Client, args *RequestResortArgs) (*RequestResortResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`RequestResort`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{RequestResort: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.RequestResort == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling contentdirectory.RequestResort()`)
|
||||
}
|
||||
|
||||
return r.Body.RequestResort, nil
|
||||
}
|
||||
|
||||
type GetShareIndexInProgressArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
}
|
||||
type GetShareIndexInProgressResponse struct {
|
||||
IsIndexing bool `xml:"IsIndexing"`
|
||||
}
|
||||
|
||||
func (s *Service) GetShareIndexInProgress(httpClient *http.Client, args *GetShareIndexInProgressArgs) (*GetShareIndexInProgressResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`GetShareIndexInProgress`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{GetShareIndexInProgress: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.GetShareIndexInProgress == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling contentdirectory.GetShareIndexInProgress()`)
|
||||
}
|
||||
|
||||
return r.Body.GetShareIndexInProgress, nil
|
||||
}
|
||||
|
||||
type GetBrowseableArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
}
|
||||
type GetBrowseableResponse struct {
|
||||
IsBrowseable bool `xml:"IsBrowseable"`
|
||||
}
|
||||
|
||||
func (s *Service) GetBrowseable(httpClient *http.Client, args *GetBrowseableArgs) (*GetBrowseableResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`GetBrowseable`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{GetBrowseable: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.GetBrowseable == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling contentdirectory.GetBrowseable()`)
|
||||
}
|
||||
|
||||
return r.Body.GetBrowseable, nil
|
||||
}
|
||||
|
||||
type SetBrowseableArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
Browseable bool `xml:"Browseable"`
|
||||
}
|
||||
type SetBrowseableResponse struct {
|
||||
}
|
||||
|
||||
func (s *Service) SetBrowseable(httpClient *http.Client, args *SetBrowseableArgs) (*SetBrowseableResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`SetBrowseable`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{SetBrowseable: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.SetBrowseable == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling contentdirectory.SetBrowseable()`)
|
||||
}
|
||||
|
||||
return r.Body.SetBrowseable, nil
|
||||
}
|
||||
+789
@@ -0,0 +1,789 @@
|
||||
package deviceproperties
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/xml"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
const (
|
||||
_ServiceURN = "urn:schemas-upnp-org:service:DeviceProperties:1"
|
||||
_EncodingSchema = "http://schemas.xmlsoap.org/soap/encoding/"
|
||||
_EnvelopeSchema = "http://schemas.xmlsoap.org/soap/envelope/"
|
||||
)
|
||||
|
||||
type Service struct {
|
||||
ControlEndpoint *url.URL
|
||||
EventEndpoint *url.URL
|
||||
}
|
||||
|
||||
func NewService(deviceUrl *url.URL) *Service {
|
||||
c, err := url.Parse(`/DeviceProperties/Control`)
|
||||
if nil != err {
|
||||
panic(err)
|
||||
}
|
||||
e, err := url.Parse(`/DeviceProperties/Event`)
|
||||
if nil != err {
|
||||
panic(err)
|
||||
}
|
||||
return &Service{
|
||||
ControlEndpoint: deviceUrl.ResolveReference(c),
|
||||
EventEndpoint: deviceUrl.ResolveReference(e),
|
||||
}
|
||||
}
|
||||
|
||||
type Envelope struct {
|
||||
XMLName xml.Name `xml:"s:Envelope"`
|
||||
Xmlns string `xml:"xmlns:s,attr"`
|
||||
EncodingStyle string `xml:"s:encodingStyle,attr"`
|
||||
Body Body `xml:"s:Body"`
|
||||
}
|
||||
type Body struct {
|
||||
XMLName xml.Name `xml:"s:Body"`
|
||||
SetLEDState *SetLEDStateArgs `xml:"u:SetLEDState,omitempty"`
|
||||
GetLEDState *GetLEDStateArgs `xml:"u:GetLEDState,omitempty"`
|
||||
AddBondedZones *AddBondedZonesArgs `xml:"u:AddBondedZones,omitempty"`
|
||||
RemoveBondedZones *RemoveBondedZonesArgs `xml:"u:RemoveBondedZones,omitempty"`
|
||||
CreateStereoPair *CreateStereoPairArgs `xml:"u:CreateStereoPair,omitempty"`
|
||||
SeparateStereoPair *SeparateStereoPairArgs `xml:"u:SeparateStereoPair,omitempty"`
|
||||
SetZoneAttributes *SetZoneAttributesArgs `xml:"u:SetZoneAttributes,omitempty"`
|
||||
GetZoneAttributes *GetZoneAttributesArgs `xml:"u:GetZoneAttributes,omitempty"`
|
||||
GetHouseholdID *GetHouseholdIDArgs `xml:"u:GetHouseholdID,omitempty"`
|
||||
GetZoneInfo *GetZoneInfoArgs `xml:"u:GetZoneInfo,omitempty"`
|
||||
SetAutoplayLinkedZones *SetAutoplayLinkedZonesArgs `xml:"u:SetAutoplayLinkedZones,omitempty"`
|
||||
GetAutoplayLinkedZones *GetAutoplayLinkedZonesArgs `xml:"u:GetAutoplayLinkedZones,omitempty"`
|
||||
SetAutoplayRoomUUID *SetAutoplayRoomUUIDArgs `xml:"u:SetAutoplayRoomUUID,omitempty"`
|
||||
GetAutoplayRoomUUID *GetAutoplayRoomUUIDArgs `xml:"u:GetAutoplayRoomUUID,omitempty"`
|
||||
SetAutoplayVolume *SetAutoplayVolumeArgs `xml:"u:SetAutoplayVolume,omitempty"`
|
||||
GetAutoplayVolume *GetAutoplayVolumeArgs `xml:"u:GetAutoplayVolume,omitempty"`
|
||||
SetUseAutoplayVolume *SetUseAutoplayVolumeArgs `xml:"u:SetUseAutoplayVolume,omitempty"`
|
||||
GetUseAutoplayVolume *GetUseAutoplayVolumeArgs `xml:"u:GetUseAutoplayVolume,omitempty"`
|
||||
AddHTSatellite *AddHTSatelliteArgs `xml:"u:AddHTSatellite,omitempty"`
|
||||
RemoveHTSatellite *RemoveHTSatelliteArgs `xml:"u:RemoveHTSatellite,omitempty"`
|
||||
EnterConfigMode *EnterConfigModeArgs `xml:"u:EnterConfigMode,omitempty"`
|
||||
ExitConfigMode *ExitConfigModeArgs `xml:"u:ExitConfigMode,omitempty"`
|
||||
GetButtonState *GetButtonStateArgs `xml:"u:GetButtonState,omitempty"`
|
||||
SetButtonLockState *SetButtonLockStateArgs `xml:"u:SetButtonLockState,omitempty"`
|
||||
GetButtonLockState *GetButtonLockStateArgs `xml:"u:GetButtonLockState,omitempty"`
|
||||
}
|
||||
type EnvelopeResponse struct {
|
||||
XMLName xml.Name `xml:"Envelope"`
|
||||
Xmlns string `xml:"xmlns:s,attr"`
|
||||
EncodingStyle string `xml:"encodingStyle,attr"`
|
||||
Body BodyResponse `xml:"Body"`
|
||||
}
|
||||
type BodyResponse struct {
|
||||
XMLName xml.Name `xml:"Body"`
|
||||
SetLEDState *SetLEDStateResponse `xml:"SetLEDStateResponse,omitempty"`
|
||||
GetLEDState *GetLEDStateResponse `xml:"GetLEDStateResponse,omitempty"`
|
||||
AddBondedZones *AddBondedZonesResponse `xml:"AddBondedZonesResponse,omitempty"`
|
||||
RemoveBondedZones *RemoveBondedZonesResponse `xml:"RemoveBondedZonesResponse,omitempty"`
|
||||
CreateStereoPair *CreateStereoPairResponse `xml:"CreateStereoPairResponse,omitempty"`
|
||||
SeparateStereoPair *SeparateStereoPairResponse `xml:"SeparateStereoPairResponse,omitempty"`
|
||||
SetZoneAttributes *SetZoneAttributesResponse `xml:"SetZoneAttributesResponse,omitempty"`
|
||||
GetZoneAttributes *GetZoneAttributesResponse `xml:"GetZoneAttributesResponse,omitempty"`
|
||||
GetHouseholdID *GetHouseholdIDResponse `xml:"GetHouseholdIDResponse,omitempty"`
|
||||
GetZoneInfo *GetZoneInfoResponse `xml:"GetZoneInfoResponse,omitempty"`
|
||||
SetAutoplayLinkedZones *SetAutoplayLinkedZonesResponse `xml:"SetAutoplayLinkedZonesResponse,omitempty"`
|
||||
GetAutoplayLinkedZones *GetAutoplayLinkedZonesResponse `xml:"GetAutoplayLinkedZonesResponse,omitempty"`
|
||||
SetAutoplayRoomUUID *SetAutoplayRoomUUIDResponse `xml:"SetAutoplayRoomUUIDResponse,omitempty"`
|
||||
GetAutoplayRoomUUID *GetAutoplayRoomUUIDResponse `xml:"GetAutoplayRoomUUIDResponse,omitempty"`
|
||||
SetAutoplayVolume *SetAutoplayVolumeResponse `xml:"SetAutoplayVolumeResponse,omitempty"`
|
||||
GetAutoplayVolume *GetAutoplayVolumeResponse `xml:"GetAutoplayVolumeResponse,omitempty"`
|
||||
SetUseAutoplayVolume *SetUseAutoplayVolumeResponse `xml:"SetUseAutoplayVolumeResponse,omitempty"`
|
||||
GetUseAutoplayVolume *GetUseAutoplayVolumeResponse `xml:"GetUseAutoplayVolumeResponse,omitempty"`
|
||||
AddHTSatellite *AddHTSatelliteResponse `xml:"AddHTSatelliteResponse,omitempty"`
|
||||
RemoveHTSatellite *RemoveHTSatelliteResponse `xml:"RemoveHTSatelliteResponse,omitempty"`
|
||||
EnterConfigMode *EnterConfigModeResponse `xml:"EnterConfigModeResponse,omitempty"`
|
||||
ExitConfigMode *ExitConfigModeResponse `xml:"ExitConfigModeResponse,omitempty"`
|
||||
GetButtonState *GetButtonStateResponse `xml:"GetButtonStateResponse,omitempty"`
|
||||
SetButtonLockState *SetButtonLockStateResponse `xml:"SetButtonLockStateResponse,omitempty"`
|
||||
GetButtonLockState *GetButtonLockStateResponse `xml:"GetButtonLockStateResponse,omitempty"`
|
||||
}
|
||||
|
||||
func (s *Service) exec(actionName string, httpClient *http.Client, envelope *Envelope) (*EnvelopeResponse, error) {
|
||||
marshaled, err := xml.Marshal(envelope)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
postBody := []byte(`<?xml version="1.0"?>`)
|
||||
postBody = append(postBody, marshaled...)
|
||||
req, err := http.NewRequest(`POST`, s.ControlEndpoint.String(), bytes.NewBuffer(postBody))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set(`Content-Type`, `text/xml; charset="utf-8"`)
|
||||
req.Header.Set(`SOAPAction`, _ServiceURN+`#`+actionName)
|
||||
res, err := httpClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
responseBody, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var envelopeResponse EnvelopeResponse
|
||||
err = xml.Unmarshal(responseBody, &envelopeResponse)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &envelopeResponse, nil
|
||||
}
|
||||
|
||||
type SetLEDStateArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
// Allowed Value: On
|
||||
// Allowed Value: Off
|
||||
DesiredLEDState string `xml:"DesiredLEDState"`
|
||||
}
|
||||
type SetLEDStateResponse struct {
|
||||
}
|
||||
|
||||
func (s *Service) SetLEDState(httpClient *http.Client, args *SetLEDStateArgs) (*SetLEDStateResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`SetLEDState`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{SetLEDState: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.SetLEDState == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling deviceproperties.SetLEDState()`)
|
||||
}
|
||||
|
||||
return r.Body.SetLEDState, nil
|
||||
}
|
||||
|
||||
type GetLEDStateArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
}
|
||||
type GetLEDStateResponse struct {
|
||||
CurrentLEDState string `xml:"CurrentLEDState"`
|
||||
}
|
||||
|
||||
func (s *Service) GetLEDState(httpClient *http.Client, args *GetLEDStateArgs) (*GetLEDStateResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`GetLEDState`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{GetLEDState: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.GetLEDState == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling deviceproperties.GetLEDState()`)
|
||||
}
|
||||
|
||||
return r.Body.GetLEDState, nil
|
||||
}
|
||||
|
||||
type AddBondedZonesArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
ChannelMapSet string `xml:"ChannelMapSet"`
|
||||
}
|
||||
type AddBondedZonesResponse struct {
|
||||
}
|
||||
|
||||
func (s *Service) AddBondedZones(httpClient *http.Client, args *AddBondedZonesArgs) (*AddBondedZonesResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`AddBondedZones`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{AddBondedZones: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.AddBondedZones == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling deviceproperties.AddBondedZones()`)
|
||||
}
|
||||
|
||||
return r.Body.AddBondedZones, nil
|
||||
}
|
||||
|
||||
type RemoveBondedZonesArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
ChannelMapSet string `xml:"ChannelMapSet"`
|
||||
KeepGrouped bool `xml:"KeepGrouped"`
|
||||
}
|
||||
type RemoveBondedZonesResponse struct {
|
||||
}
|
||||
|
||||
func (s *Service) RemoveBondedZones(httpClient *http.Client, args *RemoveBondedZonesArgs) (*RemoveBondedZonesResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`RemoveBondedZones`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{RemoveBondedZones: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.RemoveBondedZones == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling deviceproperties.RemoveBondedZones()`)
|
||||
}
|
||||
|
||||
return r.Body.RemoveBondedZones, nil
|
||||
}
|
||||
|
||||
type CreateStereoPairArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
ChannelMapSet string `xml:"ChannelMapSet"`
|
||||
}
|
||||
type CreateStereoPairResponse struct {
|
||||
}
|
||||
|
||||
func (s *Service) CreateStereoPair(httpClient *http.Client, args *CreateStereoPairArgs) (*CreateStereoPairResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`CreateStereoPair`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{CreateStereoPair: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.CreateStereoPair == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling deviceproperties.CreateStereoPair()`)
|
||||
}
|
||||
|
||||
return r.Body.CreateStereoPair, nil
|
||||
}
|
||||
|
||||
type SeparateStereoPairArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
ChannelMapSet string `xml:"ChannelMapSet"`
|
||||
}
|
||||
type SeparateStereoPairResponse struct {
|
||||
}
|
||||
|
||||
func (s *Service) SeparateStereoPair(httpClient *http.Client, args *SeparateStereoPairArgs) (*SeparateStereoPairResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`SeparateStereoPair`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{SeparateStereoPair: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.SeparateStereoPair == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling deviceproperties.SeparateStereoPair()`)
|
||||
}
|
||||
|
||||
return r.Body.SeparateStereoPair, nil
|
||||
}
|
||||
|
||||
type SetZoneAttributesArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
DesiredZoneName string `xml:"DesiredZoneName"`
|
||||
DesiredIcon string `xml:"DesiredIcon"`
|
||||
DesiredConfiguration string `xml:"DesiredConfiguration"`
|
||||
}
|
||||
type SetZoneAttributesResponse struct {
|
||||
}
|
||||
|
||||
func (s *Service) SetZoneAttributes(httpClient *http.Client, args *SetZoneAttributesArgs) (*SetZoneAttributesResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`SetZoneAttributes`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{SetZoneAttributes: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.SetZoneAttributes == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling deviceproperties.SetZoneAttributes()`)
|
||||
}
|
||||
|
||||
return r.Body.SetZoneAttributes, nil
|
||||
}
|
||||
|
||||
type GetZoneAttributesArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
}
|
||||
type GetZoneAttributesResponse struct {
|
||||
CurrentZoneName string `xml:"CurrentZoneName"`
|
||||
CurrentIcon string `xml:"CurrentIcon"`
|
||||
CurrentConfiguration string `xml:"CurrentConfiguration"`
|
||||
}
|
||||
|
||||
func (s *Service) GetZoneAttributes(httpClient *http.Client, args *GetZoneAttributesArgs) (*GetZoneAttributesResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`GetZoneAttributes`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{GetZoneAttributes: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.GetZoneAttributes == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling deviceproperties.GetZoneAttributes()`)
|
||||
}
|
||||
|
||||
return r.Body.GetZoneAttributes, nil
|
||||
}
|
||||
|
||||
type GetHouseholdIDArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
}
|
||||
type GetHouseholdIDResponse struct {
|
||||
CurrentHouseholdID string `xml:"CurrentHouseholdID"`
|
||||
}
|
||||
|
||||
func (s *Service) GetHouseholdID(httpClient *http.Client, args *GetHouseholdIDArgs) (*GetHouseholdIDResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`GetHouseholdID`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{GetHouseholdID: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.GetHouseholdID == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling deviceproperties.GetHouseholdID()`)
|
||||
}
|
||||
|
||||
return r.Body.GetHouseholdID, nil
|
||||
}
|
||||
|
||||
type GetZoneInfoArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
}
|
||||
type GetZoneInfoResponse struct {
|
||||
SerialNumber string `xml:"SerialNumber"`
|
||||
SoftwareVersion string `xml:"SoftwareVersion"`
|
||||
DisplaySoftwareVersion string `xml:"DisplaySoftwareVersion"`
|
||||
HardwareVersion string `xml:"HardwareVersion"`
|
||||
IPAddress string `xml:"IPAddress"`
|
||||
MACAddress string `xml:"MACAddress"`
|
||||
CopyrightInfo string `xml:"CopyrightInfo"`
|
||||
ExtraInfo string `xml:"ExtraInfo"`
|
||||
HTAudioIn uint32 `xml:"HTAudioIn"`
|
||||
Flags uint32 `xml:"Flags"`
|
||||
}
|
||||
|
||||
func (s *Service) GetZoneInfo(httpClient *http.Client, args *GetZoneInfoArgs) (*GetZoneInfoResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`GetZoneInfo`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{GetZoneInfo: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.GetZoneInfo == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling deviceproperties.GetZoneInfo()`)
|
||||
}
|
||||
|
||||
return r.Body.GetZoneInfo, nil
|
||||
}
|
||||
|
||||
type SetAutoplayLinkedZonesArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
IncludeLinkedZones bool `xml:"IncludeLinkedZones"`
|
||||
Source string `xml:"Source"`
|
||||
}
|
||||
type SetAutoplayLinkedZonesResponse struct {
|
||||
}
|
||||
|
||||
func (s *Service) SetAutoplayLinkedZones(httpClient *http.Client, args *SetAutoplayLinkedZonesArgs) (*SetAutoplayLinkedZonesResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`SetAutoplayLinkedZones`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{SetAutoplayLinkedZones: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.SetAutoplayLinkedZones == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling deviceproperties.SetAutoplayLinkedZones()`)
|
||||
}
|
||||
|
||||
return r.Body.SetAutoplayLinkedZones, nil
|
||||
}
|
||||
|
||||
type GetAutoplayLinkedZonesArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
Source string `xml:"Source"`
|
||||
}
|
||||
type GetAutoplayLinkedZonesResponse struct {
|
||||
IncludeLinkedZones bool `xml:"IncludeLinkedZones"`
|
||||
}
|
||||
|
||||
func (s *Service) GetAutoplayLinkedZones(httpClient *http.Client, args *GetAutoplayLinkedZonesArgs) (*GetAutoplayLinkedZonesResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`GetAutoplayLinkedZones`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{GetAutoplayLinkedZones: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.GetAutoplayLinkedZones == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling deviceproperties.GetAutoplayLinkedZones()`)
|
||||
}
|
||||
|
||||
return r.Body.GetAutoplayLinkedZones, nil
|
||||
}
|
||||
|
||||
type SetAutoplayRoomUUIDArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
RoomUUID string `xml:"RoomUUID"`
|
||||
Source string `xml:"Source"`
|
||||
}
|
||||
type SetAutoplayRoomUUIDResponse struct {
|
||||
}
|
||||
|
||||
func (s *Service) SetAutoplayRoomUUID(httpClient *http.Client, args *SetAutoplayRoomUUIDArgs) (*SetAutoplayRoomUUIDResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`SetAutoplayRoomUUID`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{SetAutoplayRoomUUID: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.SetAutoplayRoomUUID == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling deviceproperties.SetAutoplayRoomUUID()`)
|
||||
}
|
||||
|
||||
return r.Body.SetAutoplayRoomUUID, nil
|
||||
}
|
||||
|
||||
type GetAutoplayRoomUUIDArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
Source string `xml:"Source"`
|
||||
}
|
||||
type GetAutoplayRoomUUIDResponse struct {
|
||||
RoomUUID string `xml:"RoomUUID"`
|
||||
}
|
||||
|
||||
func (s *Service) GetAutoplayRoomUUID(httpClient *http.Client, args *GetAutoplayRoomUUIDArgs) (*GetAutoplayRoomUUIDResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`GetAutoplayRoomUUID`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{GetAutoplayRoomUUID: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.GetAutoplayRoomUUID == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling deviceproperties.GetAutoplayRoomUUID()`)
|
||||
}
|
||||
|
||||
return r.Body.GetAutoplayRoomUUID, nil
|
||||
}
|
||||
|
||||
type SetAutoplayVolumeArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
// Allowed Range: 0 -> 100 step: 1
|
||||
Volume uint16 `xml:"Volume"`
|
||||
Source string `xml:"Source"`
|
||||
}
|
||||
type SetAutoplayVolumeResponse struct {
|
||||
}
|
||||
|
||||
func (s *Service) SetAutoplayVolume(httpClient *http.Client, args *SetAutoplayVolumeArgs) (*SetAutoplayVolumeResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`SetAutoplayVolume`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{SetAutoplayVolume: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.SetAutoplayVolume == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling deviceproperties.SetAutoplayVolume()`)
|
||||
}
|
||||
|
||||
return r.Body.SetAutoplayVolume, nil
|
||||
}
|
||||
|
||||
type GetAutoplayVolumeArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
Source string `xml:"Source"`
|
||||
}
|
||||
type GetAutoplayVolumeResponse struct {
|
||||
CurrentVolume uint16 `xml:"CurrentVolume"`
|
||||
}
|
||||
|
||||
func (s *Service) GetAutoplayVolume(httpClient *http.Client, args *GetAutoplayVolumeArgs) (*GetAutoplayVolumeResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`GetAutoplayVolume`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{GetAutoplayVolume: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.GetAutoplayVolume == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling deviceproperties.GetAutoplayVolume()`)
|
||||
}
|
||||
|
||||
return r.Body.GetAutoplayVolume, nil
|
||||
}
|
||||
|
||||
type SetUseAutoplayVolumeArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
UseVolume bool `xml:"UseVolume"`
|
||||
Source string `xml:"Source"`
|
||||
}
|
||||
type SetUseAutoplayVolumeResponse struct {
|
||||
}
|
||||
|
||||
func (s *Service) SetUseAutoplayVolume(httpClient *http.Client, args *SetUseAutoplayVolumeArgs) (*SetUseAutoplayVolumeResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`SetUseAutoplayVolume`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{SetUseAutoplayVolume: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.SetUseAutoplayVolume == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling deviceproperties.SetUseAutoplayVolume()`)
|
||||
}
|
||||
|
||||
return r.Body.SetUseAutoplayVolume, nil
|
||||
}
|
||||
|
||||
type GetUseAutoplayVolumeArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
Source string `xml:"Source"`
|
||||
}
|
||||
type GetUseAutoplayVolumeResponse struct {
|
||||
UseVolume bool `xml:"UseVolume"`
|
||||
}
|
||||
|
||||
func (s *Service) GetUseAutoplayVolume(httpClient *http.Client, args *GetUseAutoplayVolumeArgs) (*GetUseAutoplayVolumeResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`GetUseAutoplayVolume`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{GetUseAutoplayVolume: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.GetUseAutoplayVolume == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling deviceproperties.GetUseAutoplayVolume()`)
|
||||
}
|
||||
|
||||
return r.Body.GetUseAutoplayVolume, nil
|
||||
}
|
||||
|
||||
type AddHTSatelliteArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
HTSatChanMapSet string `xml:"HTSatChanMapSet"`
|
||||
}
|
||||
type AddHTSatelliteResponse struct {
|
||||
}
|
||||
|
||||
func (s *Service) AddHTSatellite(httpClient *http.Client, args *AddHTSatelliteArgs) (*AddHTSatelliteResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`AddHTSatellite`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{AddHTSatellite: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.AddHTSatellite == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling deviceproperties.AddHTSatellite()`)
|
||||
}
|
||||
|
||||
return r.Body.AddHTSatellite, nil
|
||||
}
|
||||
|
||||
type RemoveHTSatelliteArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
SatRoomUUID string `xml:"SatRoomUUID"`
|
||||
}
|
||||
type RemoveHTSatelliteResponse struct {
|
||||
}
|
||||
|
||||
func (s *Service) RemoveHTSatellite(httpClient *http.Client, args *RemoveHTSatelliteArgs) (*RemoveHTSatelliteResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`RemoveHTSatellite`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{RemoveHTSatellite: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.RemoveHTSatellite == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling deviceproperties.RemoveHTSatellite()`)
|
||||
}
|
||||
|
||||
return r.Body.RemoveHTSatellite, nil
|
||||
}
|
||||
|
||||
type EnterConfigModeArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
Mode string `xml:"Mode"`
|
||||
Options string `xml:"Options"`
|
||||
}
|
||||
type EnterConfigModeResponse struct {
|
||||
State string `xml:"State"`
|
||||
}
|
||||
|
||||
func (s *Service) EnterConfigMode(httpClient *http.Client, args *EnterConfigModeArgs) (*EnterConfigModeResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`EnterConfigMode`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{EnterConfigMode: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.EnterConfigMode == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling deviceproperties.EnterConfigMode()`)
|
||||
}
|
||||
|
||||
return r.Body.EnterConfigMode, nil
|
||||
}
|
||||
|
||||
type ExitConfigModeArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
Options string `xml:"Options"`
|
||||
}
|
||||
type ExitConfigModeResponse struct {
|
||||
}
|
||||
|
||||
func (s *Service) ExitConfigMode(httpClient *http.Client, args *ExitConfigModeArgs) (*ExitConfigModeResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`ExitConfigMode`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{ExitConfigMode: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.ExitConfigMode == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling deviceproperties.ExitConfigMode()`)
|
||||
}
|
||||
|
||||
return r.Body.ExitConfigMode, nil
|
||||
}
|
||||
|
||||
type GetButtonStateArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
}
|
||||
type GetButtonStateResponse struct {
|
||||
State string `xml:"State"`
|
||||
}
|
||||
|
||||
func (s *Service) GetButtonState(httpClient *http.Client, args *GetButtonStateArgs) (*GetButtonStateResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`GetButtonState`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{GetButtonState: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.GetButtonState == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling deviceproperties.GetButtonState()`)
|
||||
}
|
||||
|
||||
return r.Body.GetButtonState, nil
|
||||
}
|
||||
|
||||
type SetButtonLockStateArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
// Allowed Value: On
|
||||
// Allowed Value: Off
|
||||
DesiredButtonLockState string `xml:"DesiredButtonLockState"`
|
||||
}
|
||||
type SetButtonLockStateResponse struct {
|
||||
}
|
||||
|
||||
func (s *Service) SetButtonLockState(httpClient *http.Client, args *SetButtonLockStateArgs) (*SetButtonLockStateResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`SetButtonLockState`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{SetButtonLockState: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.SetButtonLockState == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling deviceproperties.SetButtonLockState()`)
|
||||
}
|
||||
|
||||
return r.Body.SetButtonLockState, nil
|
||||
}
|
||||
|
||||
type GetButtonLockStateArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
}
|
||||
type GetButtonLockStateResponse struct {
|
||||
CurrentButtonLockState string `xml:"CurrentButtonLockState"`
|
||||
}
|
||||
|
||||
func (s *Service) GetButtonLockState(httpClient *http.Client, args *GetButtonLockStateArgs) (*GetButtonLockStateResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`GetButtonLockState`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{GetButtonLockState: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.GetButtonLockState == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling deviceproperties.GetButtonLockState()`)
|
||||
}
|
||||
|
||||
return r.Body.GetButtonLockState, nil
|
||||
}
|
||||
+200
@@ -0,0 +1,200 @@
|
||||
package groupmanagement
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/xml"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
const (
|
||||
_ServiceURN = "urn:schemas-upnp-org:service:GroupManagement:1"
|
||||
_EncodingSchema = "http://schemas.xmlsoap.org/soap/encoding/"
|
||||
_EnvelopeSchema = "http://schemas.xmlsoap.org/soap/envelope/"
|
||||
)
|
||||
|
||||
type Service struct {
|
||||
ControlEndpoint *url.URL
|
||||
EventEndpoint *url.URL
|
||||
}
|
||||
|
||||
func NewService(deviceUrl *url.URL) *Service {
|
||||
c, err := url.Parse(`/GroupManagement/Control`)
|
||||
if nil != err {
|
||||
panic(err)
|
||||
}
|
||||
e, err := url.Parse(`/GroupManagement/Event`)
|
||||
if nil != err {
|
||||
panic(err)
|
||||
}
|
||||
return &Service{
|
||||
ControlEndpoint: deviceUrl.ResolveReference(c),
|
||||
EventEndpoint: deviceUrl.ResolveReference(e),
|
||||
}
|
||||
}
|
||||
|
||||
type Envelope struct {
|
||||
XMLName xml.Name `xml:"s:Envelope"`
|
||||
Xmlns string `xml:"xmlns:s,attr"`
|
||||
EncodingStyle string `xml:"s:encodingStyle,attr"`
|
||||
Body Body `xml:"s:Body"`
|
||||
}
|
||||
type Body struct {
|
||||
XMLName xml.Name `xml:"s:Body"`
|
||||
AddMember *AddMemberArgs `xml:"u:AddMember,omitempty"`
|
||||
RemoveMember *RemoveMemberArgs `xml:"u:RemoveMember,omitempty"`
|
||||
ReportTrackBufferingResult *ReportTrackBufferingResultArgs `xml:"u:ReportTrackBufferingResult,omitempty"`
|
||||
SetSourceAreaIds *SetSourceAreaIdsArgs `xml:"u:SetSourceAreaIds,omitempty"`
|
||||
}
|
||||
type EnvelopeResponse struct {
|
||||
XMLName xml.Name `xml:"Envelope"`
|
||||
Xmlns string `xml:"xmlns:s,attr"`
|
||||
EncodingStyle string `xml:"encodingStyle,attr"`
|
||||
Body BodyResponse `xml:"Body"`
|
||||
}
|
||||
type BodyResponse struct {
|
||||
XMLName xml.Name `xml:"Body"`
|
||||
AddMember *AddMemberResponse `xml:"AddMemberResponse,omitempty"`
|
||||
RemoveMember *RemoveMemberResponse `xml:"RemoveMemberResponse,omitempty"`
|
||||
ReportTrackBufferingResult *ReportTrackBufferingResultResponse `xml:"ReportTrackBufferingResultResponse,omitempty"`
|
||||
SetSourceAreaIds *SetSourceAreaIdsResponse `xml:"SetSourceAreaIdsResponse,omitempty"`
|
||||
}
|
||||
|
||||
func (s *Service) exec(actionName string, httpClient *http.Client, envelope *Envelope) (*EnvelopeResponse, error) {
|
||||
marshaled, err := xml.Marshal(envelope)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
postBody := []byte(`<?xml version="1.0"?>`)
|
||||
postBody = append(postBody, marshaled...)
|
||||
req, err := http.NewRequest(`POST`, s.ControlEndpoint.String(), bytes.NewBuffer(postBody))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set(`Content-Type`, `text/xml; charset="utf-8"`)
|
||||
req.Header.Set(`SOAPAction`, _ServiceURN+`#`+actionName)
|
||||
res, err := httpClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
responseBody, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var envelopeResponse EnvelopeResponse
|
||||
err = xml.Unmarshal(responseBody, &envelopeResponse)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &envelopeResponse, nil
|
||||
}
|
||||
|
||||
type AddMemberArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
MemberID string `xml:"MemberID"`
|
||||
BootSeq uint32 `xml:"BootSeq"`
|
||||
}
|
||||
type AddMemberResponse struct {
|
||||
CurrentTransportSettings string `xml:"CurrentTransportSettings"`
|
||||
CurrentURI string `xml:"CurrentURI"`
|
||||
GroupUUIDJoined string `xml:"GroupUUIDJoined"`
|
||||
ResetVolumeAfter bool `xml:"ResetVolumeAfter"`
|
||||
VolumeAVTransportURI string `xml:"VolumeAVTransportURI"`
|
||||
}
|
||||
|
||||
func (s *Service) AddMember(httpClient *http.Client, args *AddMemberArgs) (*AddMemberResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`AddMember`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{AddMember: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.AddMember == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling groupmanagement.AddMember()`)
|
||||
}
|
||||
|
||||
return r.Body.AddMember, nil
|
||||
}
|
||||
|
||||
type RemoveMemberArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
MemberID string `xml:"MemberID"`
|
||||
}
|
||||
type RemoveMemberResponse struct {
|
||||
}
|
||||
|
||||
func (s *Service) RemoveMember(httpClient *http.Client, args *RemoveMemberArgs) (*RemoveMemberResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`RemoveMember`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{RemoveMember: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.RemoveMember == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling groupmanagement.RemoveMember()`)
|
||||
}
|
||||
|
||||
return r.Body.RemoveMember, nil
|
||||
}
|
||||
|
||||
type ReportTrackBufferingResultArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
MemberID string `xml:"MemberID"`
|
||||
ResultCode int32 `xml:"ResultCode"`
|
||||
}
|
||||
type ReportTrackBufferingResultResponse struct {
|
||||
}
|
||||
|
||||
func (s *Service) ReportTrackBufferingResult(httpClient *http.Client, args *ReportTrackBufferingResultArgs) (*ReportTrackBufferingResultResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`ReportTrackBufferingResult`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{ReportTrackBufferingResult: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.ReportTrackBufferingResult == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling groupmanagement.ReportTrackBufferingResult()`)
|
||||
}
|
||||
|
||||
return r.Body.ReportTrackBufferingResult, nil
|
||||
}
|
||||
|
||||
type SetSourceAreaIdsArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
DesiredSourceAreaIds string `xml:"DesiredSourceAreaIds"`
|
||||
}
|
||||
type SetSourceAreaIdsResponse struct {
|
||||
}
|
||||
|
||||
func (s *Service) SetSourceAreaIds(httpClient *http.Client, args *SetSourceAreaIdsArgs) (*SetSourceAreaIdsResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`SetSourceAreaIds`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{SetSourceAreaIds: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.SetSourceAreaIds == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling groupmanagement.SetSourceAreaIds()`)
|
||||
}
|
||||
|
||||
return r.Body.SetSourceAreaIds, nil
|
||||
}
|
||||
+254
@@ -0,0 +1,254 @@
|
||||
package grouprenderingcontrol
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/xml"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
const (
|
||||
_ServiceURN = "urn:schemas-upnp-org:service:GroupRenderingControl:1"
|
||||
_EncodingSchema = "http://schemas.xmlsoap.org/soap/encoding/"
|
||||
_EnvelopeSchema = "http://schemas.xmlsoap.org/soap/envelope/"
|
||||
)
|
||||
|
||||
type Service struct {
|
||||
ControlEndpoint *url.URL
|
||||
EventEndpoint *url.URL
|
||||
}
|
||||
|
||||
func NewService(deviceUrl *url.URL) *Service {
|
||||
c, err := url.Parse(`/MediaRenderer/GroupRenderingControl/Control`)
|
||||
if nil != err {
|
||||
panic(err)
|
||||
}
|
||||
e, err := url.Parse(`/MediaRenderer/GroupRenderingControl/Event`)
|
||||
if nil != err {
|
||||
panic(err)
|
||||
}
|
||||
return &Service{
|
||||
ControlEndpoint: deviceUrl.ResolveReference(c),
|
||||
EventEndpoint: deviceUrl.ResolveReference(e),
|
||||
}
|
||||
}
|
||||
|
||||
type Envelope struct {
|
||||
XMLName xml.Name `xml:"s:Envelope"`
|
||||
Xmlns string `xml:"xmlns:s,attr"`
|
||||
EncodingStyle string `xml:"s:encodingStyle,attr"`
|
||||
Body Body `xml:"s:Body"`
|
||||
}
|
||||
type Body struct {
|
||||
XMLName xml.Name `xml:"s:Body"`
|
||||
GetGroupMute *GetGroupMuteArgs `xml:"u:GetGroupMute,omitempty"`
|
||||
SetGroupMute *SetGroupMuteArgs `xml:"u:SetGroupMute,omitempty"`
|
||||
GetGroupVolume *GetGroupVolumeArgs `xml:"u:GetGroupVolume,omitempty"`
|
||||
SetGroupVolume *SetGroupVolumeArgs `xml:"u:SetGroupVolume,omitempty"`
|
||||
SetRelativeGroupVolume *SetRelativeGroupVolumeArgs `xml:"u:SetRelativeGroupVolume,omitempty"`
|
||||
SnapshotGroupVolume *SnapshotGroupVolumeArgs `xml:"u:SnapshotGroupVolume,omitempty"`
|
||||
}
|
||||
type EnvelopeResponse struct {
|
||||
XMLName xml.Name `xml:"Envelope"`
|
||||
Xmlns string `xml:"xmlns:s,attr"`
|
||||
EncodingStyle string `xml:"encodingStyle,attr"`
|
||||
Body BodyResponse `xml:"Body"`
|
||||
}
|
||||
type BodyResponse struct {
|
||||
XMLName xml.Name `xml:"Body"`
|
||||
GetGroupMute *GetGroupMuteResponse `xml:"GetGroupMuteResponse,omitempty"`
|
||||
SetGroupMute *SetGroupMuteResponse `xml:"SetGroupMuteResponse,omitempty"`
|
||||
GetGroupVolume *GetGroupVolumeResponse `xml:"GetGroupVolumeResponse,omitempty"`
|
||||
SetGroupVolume *SetGroupVolumeResponse `xml:"SetGroupVolumeResponse,omitempty"`
|
||||
SetRelativeGroupVolume *SetRelativeGroupVolumeResponse `xml:"SetRelativeGroupVolumeResponse,omitempty"`
|
||||
SnapshotGroupVolume *SnapshotGroupVolumeResponse `xml:"SnapshotGroupVolumeResponse,omitempty"`
|
||||
}
|
||||
|
||||
func (s *Service) exec(actionName string, httpClient *http.Client, envelope *Envelope) (*EnvelopeResponse, error) {
|
||||
marshaled, err := xml.Marshal(envelope)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
postBody := []byte(`<?xml version="1.0"?>`)
|
||||
postBody = append(postBody, marshaled...)
|
||||
req, err := http.NewRequest(`POST`, s.ControlEndpoint.String(), bytes.NewBuffer(postBody))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set(`Content-Type`, `text/xml; charset="utf-8"`)
|
||||
req.Header.Set(`SOAPAction`, _ServiceURN+`#`+actionName)
|
||||
res, err := httpClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
responseBody, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var envelopeResponse EnvelopeResponse
|
||||
err = xml.Unmarshal(responseBody, &envelopeResponse)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &envelopeResponse, nil
|
||||
}
|
||||
|
||||
type GetGroupMuteArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
InstanceID uint32 `xml:"InstanceID"`
|
||||
}
|
||||
type GetGroupMuteResponse struct {
|
||||
CurrentMute bool `xml:"CurrentMute"`
|
||||
}
|
||||
|
||||
func (s *Service) GetGroupMute(httpClient *http.Client, args *GetGroupMuteArgs) (*GetGroupMuteResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`GetGroupMute`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{GetGroupMute: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.GetGroupMute == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling grouprenderingcontrol.GetGroupMute()`)
|
||||
}
|
||||
|
||||
return r.Body.GetGroupMute, nil
|
||||
}
|
||||
|
||||
type SetGroupMuteArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
InstanceID uint32 `xml:"InstanceID"`
|
||||
DesiredMute bool `xml:"DesiredMute"`
|
||||
}
|
||||
type SetGroupMuteResponse struct {
|
||||
}
|
||||
|
||||
func (s *Service) SetGroupMute(httpClient *http.Client, args *SetGroupMuteArgs) (*SetGroupMuteResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`SetGroupMute`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{SetGroupMute: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.SetGroupMute == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling grouprenderingcontrol.SetGroupMute()`)
|
||||
}
|
||||
|
||||
return r.Body.SetGroupMute, nil
|
||||
}
|
||||
|
||||
type GetGroupVolumeArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
InstanceID uint32 `xml:"InstanceID"`
|
||||
}
|
||||
type GetGroupVolumeResponse struct {
|
||||
CurrentVolume uint16 `xml:"CurrentVolume"`
|
||||
}
|
||||
|
||||
func (s *Service) GetGroupVolume(httpClient *http.Client, args *GetGroupVolumeArgs) (*GetGroupVolumeResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`GetGroupVolume`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{GetGroupVolume: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.GetGroupVolume == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling grouprenderingcontrol.GetGroupVolume()`)
|
||||
}
|
||||
|
||||
return r.Body.GetGroupVolume, nil
|
||||
}
|
||||
|
||||
type SetGroupVolumeArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
InstanceID uint32 `xml:"InstanceID"`
|
||||
// Allowed Range: 0 -> 100 step: 1
|
||||
DesiredVolume uint16 `xml:"DesiredVolume"`
|
||||
}
|
||||
type SetGroupVolumeResponse struct {
|
||||
}
|
||||
|
||||
func (s *Service) SetGroupVolume(httpClient *http.Client, args *SetGroupVolumeArgs) (*SetGroupVolumeResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`SetGroupVolume`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{SetGroupVolume: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.SetGroupVolume == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling grouprenderingcontrol.SetGroupVolume()`)
|
||||
}
|
||||
|
||||
return r.Body.SetGroupVolume, nil
|
||||
}
|
||||
|
||||
type SetRelativeGroupVolumeArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
InstanceID uint32 `xml:"InstanceID"`
|
||||
Adjustment int32 `xml:"Adjustment"`
|
||||
}
|
||||
type SetRelativeGroupVolumeResponse struct {
|
||||
NewVolume uint16 `xml:"NewVolume"`
|
||||
}
|
||||
|
||||
func (s *Service) SetRelativeGroupVolume(httpClient *http.Client, args *SetRelativeGroupVolumeArgs) (*SetRelativeGroupVolumeResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`SetRelativeGroupVolume`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{SetRelativeGroupVolume: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.SetRelativeGroupVolume == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling grouprenderingcontrol.SetRelativeGroupVolume()`)
|
||||
}
|
||||
|
||||
return r.Body.SetRelativeGroupVolume, nil
|
||||
}
|
||||
|
||||
type SnapshotGroupVolumeArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
InstanceID uint32 `xml:"InstanceID"`
|
||||
}
|
||||
type SnapshotGroupVolumeResponse struct {
|
||||
}
|
||||
|
||||
func (s *Service) SnapshotGroupVolume(httpClient *http.Client, args *SnapshotGroupVolumeArgs) (*SnapshotGroupVolumeResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`SnapshotGroupVolume`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{SnapshotGroupVolume: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.SnapshotGroupVolume == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling grouprenderingcontrol.SnapshotGroupVolume()`)
|
||||
}
|
||||
|
||||
return r.Body.SnapshotGroupVolume, nil
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 Matthew Szatmary
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
+169
@@ -0,0 +1,169 @@
|
||||
package musicservices
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/xml"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
const (
|
||||
_ServiceURN = "urn:schemas-upnp-org:service:MusicServices:1"
|
||||
_EncodingSchema = "http://schemas.xmlsoap.org/soap/encoding/"
|
||||
_EnvelopeSchema = "http://schemas.xmlsoap.org/soap/envelope/"
|
||||
)
|
||||
|
||||
type Service struct {
|
||||
ControlEndpoint *url.URL
|
||||
EventEndpoint *url.URL
|
||||
}
|
||||
|
||||
func NewService(deviceUrl *url.URL) *Service {
|
||||
c, err := url.Parse(`/MusicServices/Control`)
|
||||
if nil != err {
|
||||
panic(err)
|
||||
}
|
||||
e, err := url.Parse(`/MusicServices/Event`)
|
||||
if nil != err {
|
||||
panic(err)
|
||||
}
|
||||
return &Service{
|
||||
ControlEndpoint: deviceUrl.ResolveReference(c),
|
||||
EventEndpoint: deviceUrl.ResolveReference(e),
|
||||
}
|
||||
}
|
||||
|
||||
type Envelope struct {
|
||||
XMLName xml.Name `xml:"s:Envelope"`
|
||||
Xmlns string `xml:"xmlns:s,attr"`
|
||||
EncodingStyle string `xml:"s:encodingStyle,attr"`
|
||||
Body Body `xml:"s:Body"`
|
||||
}
|
||||
type Body struct {
|
||||
XMLName xml.Name `xml:"s:Body"`
|
||||
GetSessionId *GetSessionIdArgs `xml:"u:GetSessionId,omitempty"`
|
||||
ListAvailableServices *ListAvailableServicesArgs `xml:"u:ListAvailableServices,omitempty"`
|
||||
UpdateAvailableServices *UpdateAvailableServicesArgs `xml:"u:UpdateAvailableServices,omitempty"`
|
||||
}
|
||||
type EnvelopeResponse struct {
|
||||
XMLName xml.Name `xml:"Envelope"`
|
||||
Xmlns string `xml:"xmlns:s,attr"`
|
||||
EncodingStyle string `xml:"encodingStyle,attr"`
|
||||
Body BodyResponse `xml:"Body"`
|
||||
}
|
||||
type BodyResponse struct {
|
||||
XMLName xml.Name `xml:"Body"`
|
||||
GetSessionId *GetSessionIdResponse `xml:"GetSessionIdResponse,omitempty"`
|
||||
ListAvailableServices *ListAvailableServicesResponse `xml:"ListAvailableServicesResponse,omitempty"`
|
||||
UpdateAvailableServices *UpdateAvailableServicesResponse `xml:"UpdateAvailableServicesResponse,omitempty"`
|
||||
}
|
||||
|
||||
func (s *Service) exec(actionName string, httpClient *http.Client, envelope *Envelope) (*EnvelopeResponse, error) {
|
||||
marshaled, err := xml.Marshal(envelope)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
postBody := []byte(`<?xml version="1.0"?>`)
|
||||
postBody = append(postBody, marshaled...)
|
||||
req, err := http.NewRequest(`POST`, s.ControlEndpoint.String(), bytes.NewBuffer(postBody))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set(`Content-Type`, `text/xml; charset="utf-8"`)
|
||||
req.Header.Set(`SOAPAction`, _ServiceURN+`#`+actionName)
|
||||
res, err := httpClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
responseBody, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var envelopeResponse EnvelopeResponse
|
||||
err = xml.Unmarshal(responseBody, &envelopeResponse)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &envelopeResponse, nil
|
||||
}
|
||||
|
||||
type GetSessionIdArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
ServiceId uint32 `xml:"ServiceId"`
|
||||
Username string `xml:"Username"`
|
||||
}
|
||||
type GetSessionIdResponse struct {
|
||||
SessionId string `xml:"SessionId"`
|
||||
}
|
||||
|
||||
func (s *Service) GetSessionId(httpClient *http.Client, args *GetSessionIdArgs) (*GetSessionIdResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`GetSessionId`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{GetSessionId: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.GetSessionId == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling musicservices.GetSessionId()`)
|
||||
}
|
||||
|
||||
return r.Body.GetSessionId, nil
|
||||
}
|
||||
|
||||
type ListAvailableServicesArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
}
|
||||
type ListAvailableServicesResponse struct {
|
||||
AvailableServiceDescriptorList string `xml:"AvailableServiceDescriptorList"`
|
||||
AvailableServiceTypeList string `xml:"AvailableServiceTypeList"`
|
||||
AvailableServiceListVersion string `xml:"AvailableServiceListVersion"`
|
||||
}
|
||||
|
||||
func (s *Service) ListAvailableServices(httpClient *http.Client, args *ListAvailableServicesArgs) (*ListAvailableServicesResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`ListAvailableServices`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{ListAvailableServices: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.ListAvailableServices == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling musicservices.ListAvailableServices()`)
|
||||
}
|
||||
|
||||
return r.Body.ListAvailableServices, nil
|
||||
}
|
||||
|
||||
type UpdateAvailableServicesArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
}
|
||||
type UpdateAvailableServicesResponse struct {
|
||||
}
|
||||
|
||||
func (s *Service) UpdateAvailableServices(httpClient *http.Client, args *UpdateAvailableServicesArgs) (*UpdateAvailableServicesResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`UpdateAvailableServices`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{UpdateAvailableServices: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.UpdateAvailableServices == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling musicservices.UpdateAvailableServices()`)
|
||||
}
|
||||
|
||||
return r.Body.UpdateAvailableServices, nil
|
||||
}
|
||||
+115
@@ -0,0 +1,115 @@
|
||||
package qplay
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/xml"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
const (
|
||||
_ServiceURN = "urn:schemas-upnp-org:service:QPlay:1"
|
||||
_EncodingSchema = "http://schemas.xmlsoap.org/soap/encoding/"
|
||||
_EnvelopeSchema = "http://schemas.xmlsoap.org/soap/envelope/"
|
||||
)
|
||||
|
||||
type Service struct {
|
||||
ControlEndpoint *url.URL
|
||||
EventEndpoint *url.URL
|
||||
}
|
||||
|
||||
func NewService(deviceUrl *url.URL) *Service {
|
||||
c, err := url.Parse(`/QPlay/Control`)
|
||||
if nil != err {
|
||||
panic(err)
|
||||
}
|
||||
e, err := url.Parse(`/QPlay/Event`)
|
||||
if nil != err {
|
||||
panic(err)
|
||||
}
|
||||
return &Service{
|
||||
ControlEndpoint: deviceUrl.ResolveReference(c),
|
||||
EventEndpoint: deviceUrl.ResolveReference(e),
|
||||
}
|
||||
}
|
||||
|
||||
type Envelope struct {
|
||||
XMLName xml.Name `xml:"s:Envelope"`
|
||||
Xmlns string `xml:"xmlns:s,attr"`
|
||||
EncodingStyle string `xml:"s:encodingStyle,attr"`
|
||||
Body Body `xml:"s:Body"`
|
||||
}
|
||||
type Body struct {
|
||||
XMLName xml.Name `xml:"s:Body"`
|
||||
QPlayAuth *QPlayAuthArgs `xml:"u:QPlayAuth,omitempty"`
|
||||
}
|
||||
type EnvelopeResponse struct {
|
||||
XMLName xml.Name `xml:"Envelope"`
|
||||
Xmlns string `xml:"xmlns:s,attr"`
|
||||
EncodingStyle string `xml:"encodingStyle,attr"`
|
||||
Body BodyResponse `xml:"Body"`
|
||||
}
|
||||
type BodyResponse struct {
|
||||
XMLName xml.Name `xml:"Body"`
|
||||
QPlayAuth *QPlayAuthResponse `xml:"QPlayAuthResponse,omitempty"`
|
||||
}
|
||||
|
||||
func (s *Service) exec(actionName string, httpClient *http.Client, envelope *Envelope) (*EnvelopeResponse, error) {
|
||||
marshaled, err := xml.Marshal(envelope)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
postBody := []byte(`<?xml version="1.0"?>`)
|
||||
postBody = append(postBody, marshaled...)
|
||||
req, err := http.NewRequest(`POST`, s.ControlEndpoint.String(), bytes.NewBuffer(postBody))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set(`Content-Type`, `text/xml; charset="utf-8"`)
|
||||
req.Header.Set(`SOAPAction`, _ServiceURN+`#`+actionName)
|
||||
res, err := httpClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
responseBody, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var envelopeResponse EnvelopeResponse
|
||||
err = xml.Unmarshal(responseBody, &envelopeResponse)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &envelopeResponse, nil
|
||||
}
|
||||
|
||||
type QPlayAuthArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
Seed string `xml:"Seed"`
|
||||
}
|
||||
type QPlayAuthResponse struct {
|
||||
Code string `xml:"Code"`
|
||||
MID string `xml:"MID"`
|
||||
DID string `xml:"DID"`
|
||||
}
|
||||
|
||||
func (s *Service) QPlayAuth(httpClient *http.Client, args *QPlayAuthArgs) (*QPlayAuthResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`QPlayAuth`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{QPlayAuth: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.QPlayAuth == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling qplay.QPlayAuth()`)
|
||||
}
|
||||
|
||||
return r.Body.QPlayAuth, nil
|
||||
}
|
||||
+435
@@ -0,0 +1,435 @@
|
||||
package queue
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/xml"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
const (
|
||||
_ServiceURN = "urn:schemas-upnp-org:service:Queue:1"
|
||||
_EncodingSchema = "http://schemas.xmlsoap.org/soap/encoding/"
|
||||
_EnvelopeSchema = "http://schemas.xmlsoap.org/soap/envelope/"
|
||||
)
|
||||
|
||||
type Service struct {
|
||||
ControlEndpoint *url.URL
|
||||
EventEndpoint *url.URL
|
||||
}
|
||||
|
||||
func NewService(deviceUrl *url.URL) *Service {
|
||||
c, err := url.Parse(`/MediaRenderer/Queue/Control`)
|
||||
if nil != err {
|
||||
panic(err)
|
||||
}
|
||||
e, err := url.Parse(`/MediaRenderer/Queue/Event`)
|
||||
if nil != err {
|
||||
panic(err)
|
||||
}
|
||||
return &Service{
|
||||
ControlEndpoint: deviceUrl.ResolveReference(c),
|
||||
EventEndpoint: deviceUrl.ResolveReference(e),
|
||||
}
|
||||
}
|
||||
|
||||
type Envelope struct {
|
||||
XMLName xml.Name `xml:"s:Envelope"`
|
||||
Xmlns string `xml:"xmlns:s,attr"`
|
||||
EncodingStyle string `xml:"s:encodingStyle,attr"`
|
||||
Body Body `xml:"s:Body"`
|
||||
}
|
||||
type Body struct {
|
||||
XMLName xml.Name `xml:"s:Body"`
|
||||
AddURI *AddURIArgs `xml:"u:AddURI,omitempty"`
|
||||
AddMultipleURIs *AddMultipleURIsArgs `xml:"u:AddMultipleURIs,omitempty"`
|
||||
AttachQueue *AttachQueueArgs `xml:"u:AttachQueue,omitempty"`
|
||||
Backup *BackupArgs `xml:"u:Backup,omitempty"`
|
||||
Browse *BrowseArgs `xml:"u:Browse,omitempty"`
|
||||
CreateQueue *CreateQueueArgs `xml:"u:CreateQueue,omitempty"`
|
||||
RemoveAllTracks *RemoveAllTracksArgs `xml:"u:RemoveAllTracks,omitempty"`
|
||||
RemoveTrackRange *RemoveTrackRangeArgs `xml:"u:RemoveTrackRange,omitempty"`
|
||||
ReorderTracks *ReorderTracksArgs `xml:"u:ReorderTracks,omitempty"`
|
||||
ReplaceAllTracks *ReplaceAllTracksArgs `xml:"u:ReplaceAllTracks,omitempty"`
|
||||
SaveAsSonosPlaylist *SaveAsSonosPlaylistArgs `xml:"u:SaveAsSonosPlaylist,omitempty"`
|
||||
}
|
||||
type EnvelopeResponse struct {
|
||||
XMLName xml.Name `xml:"Envelope"`
|
||||
Xmlns string `xml:"xmlns:s,attr"`
|
||||
EncodingStyle string `xml:"encodingStyle,attr"`
|
||||
Body BodyResponse `xml:"Body"`
|
||||
}
|
||||
type BodyResponse struct {
|
||||
XMLName xml.Name `xml:"Body"`
|
||||
AddURI *AddURIResponse `xml:"AddURIResponse,omitempty"`
|
||||
AddMultipleURIs *AddMultipleURIsResponse `xml:"AddMultipleURIsResponse,omitempty"`
|
||||
AttachQueue *AttachQueueResponse `xml:"AttachQueueResponse,omitempty"`
|
||||
Backup *BackupResponse `xml:"BackupResponse,omitempty"`
|
||||
Browse *BrowseResponse `xml:"BrowseResponse,omitempty"`
|
||||
CreateQueue *CreateQueueResponse `xml:"CreateQueueResponse,omitempty"`
|
||||
RemoveAllTracks *RemoveAllTracksResponse `xml:"RemoveAllTracksResponse,omitempty"`
|
||||
RemoveTrackRange *RemoveTrackRangeResponse `xml:"RemoveTrackRangeResponse,omitempty"`
|
||||
ReorderTracks *ReorderTracksResponse `xml:"ReorderTracksResponse,omitempty"`
|
||||
ReplaceAllTracks *ReplaceAllTracksResponse `xml:"ReplaceAllTracksResponse,omitempty"`
|
||||
SaveAsSonosPlaylist *SaveAsSonosPlaylistResponse `xml:"SaveAsSonosPlaylistResponse,omitempty"`
|
||||
}
|
||||
|
||||
func (s *Service) exec(actionName string, httpClient *http.Client, envelope *Envelope) (*EnvelopeResponse, error) {
|
||||
marshaled, err := xml.Marshal(envelope)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
postBody := []byte(`<?xml version="1.0"?>`)
|
||||
postBody = append(postBody, marshaled...)
|
||||
req, err := http.NewRequest(`POST`, s.ControlEndpoint.String(), bytes.NewBuffer(postBody))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set(`Content-Type`, `text/xml; charset="utf-8"`)
|
||||
req.Header.Set(`SOAPAction`, _ServiceURN+`#`+actionName)
|
||||
res, err := httpClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
responseBody, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var envelopeResponse EnvelopeResponse
|
||||
err = xml.Unmarshal(responseBody, &envelopeResponse)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &envelopeResponse, nil
|
||||
}
|
||||
|
||||
type AddURIArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
QueueID uint32 `xml:"QueueID"`
|
||||
UpdateID uint32 `xml:"UpdateID"`
|
||||
EnqueuedURI string `xml:"EnqueuedURI"`
|
||||
EnqueuedURIMetaData string `xml:"EnqueuedURIMetaData"`
|
||||
DesiredFirstTrackNumberEnqueued uint32 `xml:"DesiredFirstTrackNumberEnqueued"`
|
||||
EnqueueAsNext bool `xml:"EnqueueAsNext"`
|
||||
}
|
||||
type AddURIResponse struct {
|
||||
FirstTrackNumberEnqueued uint32 `xml:"FirstTrackNumberEnqueued"`
|
||||
NumTracksAdded uint32 `xml:"NumTracksAdded"`
|
||||
NewQueueLength uint32 `xml:"NewQueueLength"`
|
||||
NewUpdateID uint32 `xml:"NewUpdateID"`
|
||||
}
|
||||
|
||||
func (s *Service) AddURI(httpClient *http.Client, args *AddURIArgs) (*AddURIResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`AddURI`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{AddURI: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.AddURI == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling queue.AddURI()`)
|
||||
}
|
||||
|
||||
return r.Body.AddURI, nil
|
||||
}
|
||||
|
||||
type AddMultipleURIsArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
QueueID uint32 `xml:"QueueID"`
|
||||
UpdateID uint32 `xml:"UpdateID"`
|
||||
ContainerURI string `xml:"ContainerURI"`
|
||||
ContainerMetaData string `xml:"ContainerMetaData"`
|
||||
DesiredFirstTrackNumberEnqueued uint32 `xml:"DesiredFirstTrackNumberEnqueued"`
|
||||
EnqueueAsNext bool `xml:"EnqueueAsNext"`
|
||||
NumberOfURIs uint32 `xml:"NumberOfURIs"`
|
||||
EnqueuedURIsAndMetaData string `xml:"EnqueuedURIsAndMetaData"`
|
||||
}
|
||||
type AddMultipleURIsResponse struct {
|
||||
FirstTrackNumberEnqueued uint32 `xml:"FirstTrackNumberEnqueued"`
|
||||
NumTracksAdded uint32 `xml:"NumTracksAdded"`
|
||||
NewQueueLength uint32 `xml:"NewQueueLength"`
|
||||
NewUpdateID uint32 `xml:"NewUpdateID"`
|
||||
}
|
||||
|
||||
func (s *Service) AddMultipleURIs(httpClient *http.Client, args *AddMultipleURIsArgs) (*AddMultipleURIsResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`AddMultipleURIs`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{AddMultipleURIs: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.AddMultipleURIs == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling queue.AddMultipleURIs()`)
|
||||
}
|
||||
|
||||
return r.Body.AddMultipleURIs, nil
|
||||
}
|
||||
|
||||
type AttachQueueArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
QueueOwnerID string `xml:"QueueOwnerID"`
|
||||
}
|
||||
type AttachQueueResponse struct {
|
||||
QueueID uint32 `xml:"QueueID"`
|
||||
QueueOwnerContext string `xml:"QueueOwnerContext"`
|
||||
}
|
||||
|
||||
func (s *Service) AttachQueue(httpClient *http.Client, args *AttachQueueArgs) (*AttachQueueResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`AttachQueue`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{AttachQueue: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.AttachQueue == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling queue.AttachQueue()`)
|
||||
}
|
||||
|
||||
return r.Body.AttachQueue, nil
|
||||
}
|
||||
|
||||
type BackupArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
}
|
||||
type BackupResponse struct {
|
||||
}
|
||||
|
||||
func (s *Service) Backup(httpClient *http.Client, args *BackupArgs) (*BackupResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`Backup`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{Backup: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.Backup == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling queue.Backup()`)
|
||||
}
|
||||
|
||||
return r.Body.Backup, nil
|
||||
}
|
||||
|
||||
type BrowseArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
QueueID uint32 `xml:"QueueID"`
|
||||
StartingIndex uint32 `xml:"StartingIndex"`
|
||||
RequestedCount uint32 `xml:"RequestedCount"`
|
||||
}
|
||||
type BrowseResponse struct {
|
||||
Result string `xml:"Result"`
|
||||
NumberReturned uint32 `xml:"NumberReturned"`
|
||||
TotalMatches uint32 `xml:"TotalMatches"`
|
||||
UpdateID uint32 `xml:"UpdateID"`
|
||||
}
|
||||
|
||||
func (s *Service) Browse(httpClient *http.Client, args *BrowseArgs) (*BrowseResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`Browse`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{Browse: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.Browse == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling queue.Browse()`)
|
||||
}
|
||||
|
||||
return r.Body.Browse, nil
|
||||
}
|
||||
|
||||
type CreateQueueArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
QueueOwnerID string `xml:"QueueOwnerID"`
|
||||
QueueOwnerContext string `xml:"QueueOwnerContext"`
|
||||
QueuePolicy string `xml:"QueuePolicy"`
|
||||
}
|
||||
type CreateQueueResponse struct {
|
||||
QueueID uint32 `xml:"QueueID"`
|
||||
}
|
||||
|
||||
func (s *Service) CreateQueue(httpClient *http.Client, args *CreateQueueArgs) (*CreateQueueResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`CreateQueue`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{CreateQueue: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.CreateQueue == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling queue.CreateQueue()`)
|
||||
}
|
||||
|
||||
return r.Body.CreateQueue, nil
|
||||
}
|
||||
|
||||
type RemoveAllTracksArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
QueueID uint32 `xml:"QueueID"`
|
||||
UpdateID uint32 `xml:"UpdateID"`
|
||||
}
|
||||
type RemoveAllTracksResponse struct {
|
||||
NewUpdateID uint32 `xml:"NewUpdateID"`
|
||||
}
|
||||
|
||||
func (s *Service) RemoveAllTracks(httpClient *http.Client, args *RemoveAllTracksArgs) (*RemoveAllTracksResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`RemoveAllTracks`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{RemoveAllTracks: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.RemoveAllTracks == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling queue.RemoveAllTracks()`)
|
||||
}
|
||||
|
||||
return r.Body.RemoveAllTracks, nil
|
||||
}
|
||||
|
||||
type RemoveTrackRangeArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
QueueID uint32 `xml:"QueueID"`
|
||||
UpdateID uint32 `xml:"UpdateID"`
|
||||
StartingIndex uint32 `xml:"StartingIndex"`
|
||||
NumberOfTracks uint32 `xml:"NumberOfTracks"`
|
||||
}
|
||||
type RemoveTrackRangeResponse struct {
|
||||
NewUpdateID uint32 `xml:"NewUpdateID"`
|
||||
}
|
||||
|
||||
func (s *Service) RemoveTrackRange(httpClient *http.Client, args *RemoveTrackRangeArgs) (*RemoveTrackRangeResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`RemoveTrackRange`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{RemoveTrackRange: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.RemoveTrackRange == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling queue.RemoveTrackRange()`)
|
||||
}
|
||||
|
||||
return r.Body.RemoveTrackRange, nil
|
||||
}
|
||||
|
||||
type ReorderTracksArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
QueueID uint32 `xml:"QueueID"`
|
||||
StartingIndex uint32 `xml:"StartingIndex"`
|
||||
NumberOfTracks uint32 `xml:"NumberOfTracks"`
|
||||
InsertBefore uint32 `xml:"InsertBefore"`
|
||||
UpdateID uint32 `xml:"UpdateID"`
|
||||
}
|
||||
type ReorderTracksResponse struct {
|
||||
NewUpdateID uint32 `xml:"NewUpdateID"`
|
||||
}
|
||||
|
||||
func (s *Service) ReorderTracks(httpClient *http.Client, args *ReorderTracksArgs) (*ReorderTracksResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`ReorderTracks`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{ReorderTracks: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.ReorderTracks == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling queue.ReorderTracks()`)
|
||||
}
|
||||
|
||||
return r.Body.ReorderTracks, nil
|
||||
}
|
||||
|
||||
type ReplaceAllTracksArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
QueueID uint32 `xml:"QueueID"`
|
||||
UpdateID uint32 `xml:"UpdateID"`
|
||||
ContainerURI string `xml:"ContainerURI"`
|
||||
ContainerMetaData string `xml:"ContainerMetaData"`
|
||||
CurrentTrackIndex uint32 `xml:"CurrentTrackIndex"`
|
||||
NewCurrentTrackIndices string `xml:"NewCurrentTrackIndices"`
|
||||
NumberOfURIs uint32 `xml:"NumberOfURIs"`
|
||||
EnqueuedURIsAndMetaData string `xml:"EnqueuedURIsAndMetaData"`
|
||||
}
|
||||
type ReplaceAllTracksResponse struct {
|
||||
NewQueueLength uint32 `xml:"NewQueueLength"`
|
||||
NewUpdateID uint32 `xml:"NewUpdateID"`
|
||||
}
|
||||
|
||||
func (s *Service) ReplaceAllTracks(httpClient *http.Client, args *ReplaceAllTracksArgs) (*ReplaceAllTracksResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`ReplaceAllTracks`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{ReplaceAllTracks: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.ReplaceAllTracks == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling queue.ReplaceAllTracks()`)
|
||||
}
|
||||
|
||||
return r.Body.ReplaceAllTracks, nil
|
||||
}
|
||||
|
||||
type SaveAsSonosPlaylistArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
QueueID uint32 `xml:"QueueID"`
|
||||
Title string `xml:"Title"`
|
||||
ObjectID string `xml:"ObjectID"`
|
||||
}
|
||||
type SaveAsSonosPlaylistResponse struct {
|
||||
AssignedObjectID string `xml:"AssignedObjectID"`
|
||||
}
|
||||
|
||||
func (s *Service) SaveAsSonosPlaylist(httpClient *http.Client, args *SaveAsSonosPlaylistArgs) (*SaveAsSonosPlaylistResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`SaveAsSonosPlaylist`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{SaveAsSonosPlaylist: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.SaveAsSonosPlaylist == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling queue.SaveAsSonosPlaylist()`)
|
||||
}
|
||||
|
||||
return r.Body.SaveAsSonosPlaylist, nil
|
||||
}
|
||||
+940
@@ -0,0 +1,940 @@
|
||||
package renderingcontrol
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/xml"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
const (
|
||||
_ServiceURN = "urn:schemas-upnp-org:service:RenderingControl:1"
|
||||
_EncodingSchema = "http://schemas.xmlsoap.org/soap/encoding/"
|
||||
_EnvelopeSchema = "http://schemas.xmlsoap.org/soap/envelope/"
|
||||
)
|
||||
|
||||
type Service struct {
|
||||
ControlEndpoint *url.URL
|
||||
EventEndpoint *url.URL
|
||||
}
|
||||
|
||||
func NewService(deviceUrl *url.URL) *Service {
|
||||
c, err := url.Parse(`/MediaRenderer/RenderingControl/Control`)
|
||||
if nil != err {
|
||||
panic(err)
|
||||
}
|
||||
e, err := url.Parse(`/MediaRenderer/RenderingControl/Event`)
|
||||
if nil != err {
|
||||
panic(err)
|
||||
}
|
||||
return &Service{
|
||||
ControlEndpoint: deviceUrl.ResolveReference(c),
|
||||
EventEndpoint: deviceUrl.ResolveReference(e),
|
||||
}
|
||||
}
|
||||
|
||||
type Envelope struct {
|
||||
XMLName xml.Name `xml:"s:Envelope"`
|
||||
Xmlns string `xml:"xmlns:s,attr"`
|
||||
EncodingStyle string `xml:"s:encodingStyle,attr"`
|
||||
Body Body `xml:"s:Body"`
|
||||
}
|
||||
type Body struct {
|
||||
XMLName xml.Name `xml:"s:Body"`
|
||||
GetMute *GetMuteArgs `xml:"u:GetMute,omitempty"`
|
||||
SetMute *SetMuteArgs `xml:"u:SetMute,omitempty"`
|
||||
ResetBasicEQ *ResetBasicEQArgs `xml:"u:ResetBasicEQ,omitempty"`
|
||||
ResetExtEQ *ResetExtEQArgs `xml:"u:ResetExtEQ,omitempty"`
|
||||
GetVolume *GetVolumeArgs `xml:"u:GetVolume,omitempty"`
|
||||
SetVolume *SetVolumeArgs `xml:"u:SetVolume,omitempty"`
|
||||
SetRelativeVolume *SetRelativeVolumeArgs `xml:"u:SetRelativeVolume,omitempty"`
|
||||
GetVolumeDB *GetVolumeDBArgs `xml:"u:GetVolumeDB,omitempty"`
|
||||
SetVolumeDB *SetVolumeDBArgs `xml:"u:SetVolumeDB,omitempty"`
|
||||
GetVolumeDBRange *GetVolumeDBRangeArgs `xml:"u:GetVolumeDBRange,omitempty"`
|
||||
GetBass *GetBassArgs `xml:"u:GetBass,omitempty"`
|
||||
SetBass *SetBassArgs `xml:"u:SetBass,omitempty"`
|
||||
GetTreble *GetTrebleArgs `xml:"u:GetTreble,omitempty"`
|
||||
SetTreble *SetTrebleArgs `xml:"u:SetTreble,omitempty"`
|
||||
GetEQ *GetEQArgs `xml:"u:GetEQ,omitempty"`
|
||||
SetEQ *SetEQArgs `xml:"u:SetEQ,omitempty"`
|
||||
GetLoudness *GetLoudnessArgs `xml:"u:GetLoudness,omitempty"`
|
||||
SetLoudness *SetLoudnessArgs `xml:"u:SetLoudness,omitempty"`
|
||||
GetSupportsOutputFixed *GetSupportsOutputFixedArgs `xml:"u:GetSupportsOutputFixed,omitempty"`
|
||||
GetOutputFixed *GetOutputFixedArgs `xml:"u:GetOutputFixed,omitempty"`
|
||||
SetOutputFixed *SetOutputFixedArgs `xml:"u:SetOutputFixed,omitempty"`
|
||||
GetHeadphoneConnected *GetHeadphoneConnectedArgs `xml:"u:GetHeadphoneConnected,omitempty"`
|
||||
RampToVolume *RampToVolumeArgs `xml:"u:RampToVolume,omitempty"`
|
||||
RestoreVolumePriorToRamp *RestoreVolumePriorToRampArgs `xml:"u:RestoreVolumePriorToRamp,omitempty"`
|
||||
SetChannelMap *SetChannelMapArgs `xml:"u:SetChannelMap,omitempty"`
|
||||
SetRoomCalibrationX *SetRoomCalibrationXArgs `xml:"u:SetRoomCalibrationX,omitempty"`
|
||||
GetRoomCalibrationStatus *GetRoomCalibrationStatusArgs `xml:"u:GetRoomCalibrationStatus,omitempty"`
|
||||
SetRoomCalibrationStatus *SetRoomCalibrationStatusArgs `xml:"u:SetRoomCalibrationStatus,omitempty"`
|
||||
}
|
||||
type EnvelopeResponse struct {
|
||||
XMLName xml.Name `xml:"Envelope"`
|
||||
Xmlns string `xml:"xmlns:s,attr"`
|
||||
EncodingStyle string `xml:"encodingStyle,attr"`
|
||||
Body BodyResponse `xml:"Body"`
|
||||
}
|
||||
type BodyResponse struct {
|
||||
XMLName xml.Name `xml:"Body"`
|
||||
GetMute *GetMuteResponse `xml:"GetMuteResponse,omitempty"`
|
||||
SetMute *SetMuteResponse `xml:"SetMuteResponse,omitempty"`
|
||||
ResetBasicEQ *ResetBasicEQResponse `xml:"ResetBasicEQResponse,omitempty"`
|
||||
ResetExtEQ *ResetExtEQResponse `xml:"ResetExtEQResponse,omitempty"`
|
||||
GetVolume *GetVolumeResponse `xml:"GetVolumeResponse,omitempty"`
|
||||
SetVolume *SetVolumeResponse `xml:"SetVolumeResponse,omitempty"`
|
||||
SetRelativeVolume *SetRelativeVolumeResponse `xml:"SetRelativeVolumeResponse,omitempty"`
|
||||
GetVolumeDB *GetVolumeDBResponse `xml:"GetVolumeDBResponse,omitempty"`
|
||||
SetVolumeDB *SetVolumeDBResponse `xml:"SetVolumeDBResponse,omitempty"`
|
||||
GetVolumeDBRange *GetVolumeDBRangeResponse `xml:"GetVolumeDBRangeResponse,omitempty"`
|
||||
GetBass *GetBassResponse `xml:"GetBassResponse,omitempty"`
|
||||
SetBass *SetBassResponse `xml:"SetBassResponse,omitempty"`
|
||||
GetTreble *GetTrebleResponse `xml:"GetTrebleResponse,omitempty"`
|
||||
SetTreble *SetTrebleResponse `xml:"SetTrebleResponse,omitempty"`
|
||||
GetEQ *GetEQResponse `xml:"GetEQResponse,omitempty"`
|
||||
SetEQ *SetEQResponse `xml:"SetEQResponse,omitempty"`
|
||||
GetLoudness *GetLoudnessResponse `xml:"GetLoudnessResponse,omitempty"`
|
||||
SetLoudness *SetLoudnessResponse `xml:"SetLoudnessResponse,omitempty"`
|
||||
GetSupportsOutputFixed *GetSupportsOutputFixedResponse `xml:"GetSupportsOutputFixedResponse,omitempty"`
|
||||
GetOutputFixed *GetOutputFixedResponse `xml:"GetOutputFixedResponse,omitempty"`
|
||||
SetOutputFixed *SetOutputFixedResponse `xml:"SetOutputFixedResponse,omitempty"`
|
||||
GetHeadphoneConnected *GetHeadphoneConnectedResponse `xml:"GetHeadphoneConnectedResponse,omitempty"`
|
||||
RampToVolume *RampToVolumeResponse `xml:"RampToVolumeResponse,omitempty"`
|
||||
RestoreVolumePriorToRamp *RestoreVolumePriorToRampResponse `xml:"RestoreVolumePriorToRampResponse,omitempty"`
|
||||
SetChannelMap *SetChannelMapResponse `xml:"SetChannelMapResponse,omitempty"`
|
||||
SetRoomCalibrationX *SetRoomCalibrationXResponse `xml:"SetRoomCalibrationXResponse,omitempty"`
|
||||
GetRoomCalibrationStatus *GetRoomCalibrationStatusResponse `xml:"GetRoomCalibrationStatusResponse,omitempty"`
|
||||
SetRoomCalibrationStatus *SetRoomCalibrationStatusResponse `xml:"SetRoomCalibrationStatusResponse,omitempty"`
|
||||
}
|
||||
|
||||
func (s *Service) exec(actionName string, httpClient *http.Client, envelope *Envelope) (*EnvelopeResponse, error) {
|
||||
marshaled, err := xml.Marshal(envelope)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
postBody := []byte(`<?xml version="1.0"?>`)
|
||||
postBody = append(postBody, marshaled...)
|
||||
req, err := http.NewRequest(`POST`, s.ControlEndpoint.String(), bytes.NewBuffer(postBody))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set(`Content-Type`, `text/xml; charset="utf-8"`)
|
||||
req.Header.Set(`SOAPAction`, _ServiceURN+`#`+actionName)
|
||||
res, err := httpClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
responseBody, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var envelopeResponse EnvelopeResponse
|
||||
err = xml.Unmarshal(responseBody, &envelopeResponse)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &envelopeResponse, nil
|
||||
}
|
||||
|
||||
type GetMuteArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
InstanceID uint32 `xml:"InstanceID"`
|
||||
// Allowed Value: Master
|
||||
// Allowed Value: LF
|
||||
// Allowed Value: RF
|
||||
// Allowed Value: SpeakerOnly
|
||||
Channel string `xml:"Channel"`
|
||||
}
|
||||
type GetMuteResponse struct {
|
||||
CurrentMute bool `xml:"CurrentMute"`
|
||||
}
|
||||
|
||||
func (s *Service) GetMute(httpClient *http.Client, args *GetMuteArgs) (*GetMuteResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`GetMute`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{GetMute: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.GetMute == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling renderingcontrol.GetMute()`)
|
||||
}
|
||||
|
||||
return r.Body.GetMute, nil
|
||||
}
|
||||
|
||||
type SetMuteArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
InstanceID uint32 `xml:"InstanceID"`
|
||||
// Allowed Value: Master
|
||||
// Allowed Value: LF
|
||||
// Allowed Value: RF
|
||||
// Allowed Value: SpeakerOnly
|
||||
Channel string `xml:"Channel"`
|
||||
DesiredMute bool `xml:"DesiredMute"`
|
||||
}
|
||||
type SetMuteResponse struct {
|
||||
}
|
||||
|
||||
func (s *Service) SetMute(httpClient *http.Client, args *SetMuteArgs) (*SetMuteResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`SetMute`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{SetMute: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.SetMute == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling renderingcontrol.SetMute()`)
|
||||
}
|
||||
|
||||
return r.Body.SetMute, nil
|
||||
}
|
||||
|
||||
type ResetBasicEQArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
InstanceID uint32 `xml:"InstanceID"`
|
||||
}
|
||||
type ResetBasicEQResponse struct {
|
||||
Bass int16 `xml:"Bass"`
|
||||
Treble int16 `xml:"Treble"`
|
||||
Loudness bool `xml:"Loudness"`
|
||||
LeftVolume uint16 `xml:"LeftVolume"`
|
||||
RightVolume uint16 `xml:"RightVolume"`
|
||||
}
|
||||
|
||||
func (s *Service) ResetBasicEQ(httpClient *http.Client, args *ResetBasicEQArgs) (*ResetBasicEQResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`ResetBasicEQ`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{ResetBasicEQ: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.ResetBasicEQ == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling renderingcontrol.ResetBasicEQ()`)
|
||||
}
|
||||
|
||||
return r.Body.ResetBasicEQ, nil
|
||||
}
|
||||
|
||||
type ResetExtEQArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
InstanceID uint32 `xml:"InstanceID"`
|
||||
EQType string `xml:"EQType"`
|
||||
}
|
||||
type ResetExtEQResponse struct {
|
||||
}
|
||||
|
||||
func (s *Service) ResetExtEQ(httpClient *http.Client, args *ResetExtEQArgs) (*ResetExtEQResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`ResetExtEQ`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{ResetExtEQ: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.ResetExtEQ == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling renderingcontrol.ResetExtEQ()`)
|
||||
}
|
||||
|
||||
return r.Body.ResetExtEQ, nil
|
||||
}
|
||||
|
||||
type GetVolumeArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
InstanceID uint32 `xml:"InstanceID"`
|
||||
// Allowed Value: Master
|
||||
// Allowed Value: LF
|
||||
// Allowed Value: RF
|
||||
Channel string `xml:"Channel"`
|
||||
}
|
||||
type GetVolumeResponse struct {
|
||||
CurrentVolume uint16 `xml:"CurrentVolume"`
|
||||
}
|
||||
|
||||
func (s *Service) GetVolume(httpClient *http.Client, args *GetVolumeArgs) (*GetVolumeResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`GetVolume`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{GetVolume: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.GetVolume == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling renderingcontrol.GetVolume()`)
|
||||
}
|
||||
|
||||
return r.Body.GetVolume, nil
|
||||
}
|
||||
|
||||
type SetVolumeArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
InstanceID uint32 `xml:"InstanceID"`
|
||||
// Allowed Value: Master
|
||||
// Allowed Value: LF
|
||||
// Allowed Value: RF
|
||||
Channel string `xml:"Channel"`
|
||||
// Allowed Range: 0 -> 100 step: 1
|
||||
DesiredVolume uint16 `xml:"DesiredVolume"`
|
||||
}
|
||||
type SetVolumeResponse struct {
|
||||
}
|
||||
|
||||
func (s *Service) SetVolume(httpClient *http.Client, args *SetVolumeArgs) (*SetVolumeResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`SetVolume`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{SetVolume: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.SetVolume == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling renderingcontrol.SetVolume()`)
|
||||
}
|
||||
|
||||
return r.Body.SetVolume, nil
|
||||
}
|
||||
|
||||
type SetRelativeVolumeArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
InstanceID uint32 `xml:"InstanceID"`
|
||||
// Allowed Value: Master
|
||||
// Allowed Value: LF
|
||||
// Allowed Value: RF
|
||||
Channel string `xml:"Channel"`
|
||||
Adjustment int32 `xml:"Adjustment"`
|
||||
}
|
||||
type SetRelativeVolumeResponse struct {
|
||||
NewVolume uint16 `xml:"NewVolume"`
|
||||
}
|
||||
|
||||
func (s *Service) SetRelativeVolume(httpClient *http.Client, args *SetRelativeVolumeArgs) (*SetRelativeVolumeResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`SetRelativeVolume`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{SetRelativeVolume: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.SetRelativeVolume == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling renderingcontrol.SetRelativeVolume()`)
|
||||
}
|
||||
|
||||
return r.Body.SetRelativeVolume, nil
|
||||
}
|
||||
|
||||
type GetVolumeDBArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
InstanceID uint32 `xml:"InstanceID"`
|
||||
// Allowed Value: Master
|
||||
// Allowed Value: LF
|
||||
// Allowed Value: RF
|
||||
Channel string `xml:"Channel"`
|
||||
}
|
||||
type GetVolumeDBResponse struct {
|
||||
CurrentVolume int16 `xml:"CurrentVolume"`
|
||||
}
|
||||
|
||||
func (s *Service) GetVolumeDB(httpClient *http.Client, args *GetVolumeDBArgs) (*GetVolumeDBResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`GetVolumeDB`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{GetVolumeDB: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.GetVolumeDB == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling renderingcontrol.GetVolumeDB()`)
|
||||
}
|
||||
|
||||
return r.Body.GetVolumeDB, nil
|
||||
}
|
||||
|
||||
type SetVolumeDBArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
InstanceID uint32 `xml:"InstanceID"`
|
||||
// Allowed Value: Master
|
||||
// Allowed Value: LF
|
||||
// Allowed Value: RF
|
||||
Channel string `xml:"Channel"`
|
||||
DesiredVolume int16 `xml:"DesiredVolume"`
|
||||
}
|
||||
type SetVolumeDBResponse struct {
|
||||
}
|
||||
|
||||
func (s *Service) SetVolumeDB(httpClient *http.Client, args *SetVolumeDBArgs) (*SetVolumeDBResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`SetVolumeDB`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{SetVolumeDB: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.SetVolumeDB == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling renderingcontrol.SetVolumeDB()`)
|
||||
}
|
||||
|
||||
return r.Body.SetVolumeDB, nil
|
||||
}
|
||||
|
||||
type GetVolumeDBRangeArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
InstanceID uint32 `xml:"InstanceID"`
|
||||
// Allowed Value: Master
|
||||
// Allowed Value: LF
|
||||
// Allowed Value: RF
|
||||
Channel string `xml:"Channel"`
|
||||
}
|
||||
type GetVolumeDBRangeResponse struct {
|
||||
MinValue int16 `xml:"MinValue"`
|
||||
MaxValue int16 `xml:"MaxValue"`
|
||||
}
|
||||
|
||||
func (s *Service) GetVolumeDBRange(httpClient *http.Client, args *GetVolumeDBRangeArgs) (*GetVolumeDBRangeResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`GetVolumeDBRange`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{GetVolumeDBRange: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.GetVolumeDBRange == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling renderingcontrol.GetVolumeDBRange()`)
|
||||
}
|
||||
|
||||
return r.Body.GetVolumeDBRange, nil
|
||||
}
|
||||
|
||||
type GetBassArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
InstanceID uint32 `xml:"InstanceID"`
|
||||
}
|
||||
type GetBassResponse struct {
|
||||
CurrentBass int16 `xml:"CurrentBass"`
|
||||
}
|
||||
|
||||
func (s *Service) GetBass(httpClient *http.Client, args *GetBassArgs) (*GetBassResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`GetBass`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{GetBass: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.GetBass == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling renderingcontrol.GetBass()`)
|
||||
}
|
||||
|
||||
return r.Body.GetBass, nil
|
||||
}
|
||||
|
||||
type SetBassArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
InstanceID uint32 `xml:"InstanceID"`
|
||||
// Allowed Range: -10 -> 10 step: 1
|
||||
DesiredBass int16 `xml:"DesiredBass"`
|
||||
}
|
||||
type SetBassResponse struct {
|
||||
}
|
||||
|
||||
func (s *Service) SetBass(httpClient *http.Client, args *SetBassArgs) (*SetBassResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`SetBass`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{SetBass: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.SetBass == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling renderingcontrol.SetBass()`)
|
||||
}
|
||||
|
||||
return r.Body.SetBass, nil
|
||||
}
|
||||
|
||||
type GetTrebleArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
InstanceID uint32 `xml:"InstanceID"`
|
||||
}
|
||||
type GetTrebleResponse struct {
|
||||
CurrentTreble int16 `xml:"CurrentTreble"`
|
||||
}
|
||||
|
||||
func (s *Service) GetTreble(httpClient *http.Client, args *GetTrebleArgs) (*GetTrebleResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`GetTreble`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{GetTreble: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.GetTreble == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling renderingcontrol.GetTreble()`)
|
||||
}
|
||||
|
||||
return r.Body.GetTreble, nil
|
||||
}
|
||||
|
||||
type SetTrebleArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
InstanceID uint32 `xml:"InstanceID"`
|
||||
// Allowed Range: -10 -> 10 step: 1
|
||||
DesiredTreble int16 `xml:"DesiredTreble"`
|
||||
}
|
||||
type SetTrebleResponse struct {
|
||||
}
|
||||
|
||||
func (s *Service) SetTreble(httpClient *http.Client, args *SetTrebleArgs) (*SetTrebleResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`SetTreble`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{SetTreble: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.SetTreble == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling renderingcontrol.SetTreble()`)
|
||||
}
|
||||
|
||||
return r.Body.SetTreble, nil
|
||||
}
|
||||
|
||||
type GetEQArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
InstanceID uint32 `xml:"InstanceID"`
|
||||
EQType string `xml:"EQType"`
|
||||
}
|
||||
type GetEQResponse struct {
|
||||
CurrentValue int16 `xml:"CurrentValue"`
|
||||
}
|
||||
|
||||
func (s *Service) GetEQ(httpClient *http.Client, args *GetEQArgs) (*GetEQResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`GetEQ`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{GetEQ: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.GetEQ == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling renderingcontrol.GetEQ()`)
|
||||
}
|
||||
|
||||
return r.Body.GetEQ, nil
|
||||
}
|
||||
|
||||
type SetEQArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
InstanceID uint32 `xml:"InstanceID"`
|
||||
EQType string `xml:"EQType"`
|
||||
DesiredValue int16 `xml:"DesiredValue"`
|
||||
}
|
||||
type SetEQResponse struct {
|
||||
}
|
||||
|
||||
func (s *Service) SetEQ(httpClient *http.Client, args *SetEQArgs) (*SetEQResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`SetEQ`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{SetEQ: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.SetEQ == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling renderingcontrol.SetEQ()`)
|
||||
}
|
||||
|
||||
return r.Body.SetEQ, nil
|
||||
}
|
||||
|
||||
type GetLoudnessArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
InstanceID uint32 `xml:"InstanceID"`
|
||||
// Allowed Value: Master
|
||||
// Allowed Value: LF
|
||||
// Allowed Value: RF
|
||||
Channel string `xml:"Channel"`
|
||||
}
|
||||
type GetLoudnessResponse struct {
|
||||
CurrentLoudness bool `xml:"CurrentLoudness"`
|
||||
}
|
||||
|
||||
func (s *Service) GetLoudness(httpClient *http.Client, args *GetLoudnessArgs) (*GetLoudnessResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`GetLoudness`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{GetLoudness: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.GetLoudness == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling renderingcontrol.GetLoudness()`)
|
||||
}
|
||||
|
||||
return r.Body.GetLoudness, nil
|
||||
}
|
||||
|
||||
type SetLoudnessArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
InstanceID uint32 `xml:"InstanceID"`
|
||||
// Allowed Value: Master
|
||||
// Allowed Value: LF
|
||||
// Allowed Value: RF
|
||||
Channel string `xml:"Channel"`
|
||||
DesiredLoudness bool `xml:"DesiredLoudness"`
|
||||
}
|
||||
type SetLoudnessResponse struct {
|
||||
}
|
||||
|
||||
func (s *Service) SetLoudness(httpClient *http.Client, args *SetLoudnessArgs) (*SetLoudnessResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`SetLoudness`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{SetLoudness: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.SetLoudness == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling renderingcontrol.SetLoudness()`)
|
||||
}
|
||||
|
||||
return r.Body.SetLoudness, nil
|
||||
}
|
||||
|
||||
type GetSupportsOutputFixedArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
InstanceID uint32 `xml:"InstanceID"`
|
||||
}
|
||||
type GetSupportsOutputFixedResponse struct {
|
||||
CurrentSupportsFixed bool `xml:"CurrentSupportsFixed"`
|
||||
}
|
||||
|
||||
func (s *Service) GetSupportsOutputFixed(httpClient *http.Client, args *GetSupportsOutputFixedArgs) (*GetSupportsOutputFixedResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`GetSupportsOutputFixed`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{GetSupportsOutputFixed: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.GetSupportsOutputFixed == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling renderingcontrol.GetSupportsOutputFixed()`)
|
||||
}
|
||||
|
||||
return r.Body.GetSupportsOutputFixed, nil
|
||||
}
|
||||
|
||||
type GetOutputFixedArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
InstanceID uint32 `xml:"InstanceID"`
|
||||
}
|
||||
type GetOutputFixedResponse struct {
|
||||
CurrentFixed bool `xml:"CurrentFixed"`
|
||||
}
|
||||
|
||||
func (s *Service) GetOutputFixed(httpClient *http.Client, args *GetOutputFixedArgs) (*GetOutputFixedResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`GetOutputFixed`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{GetOutputFixed: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.GetOutputFixed == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling renderingcontrol.GetOutputFixed()`)
|
||||
}
|
||||
|
||||
return r.Body.GetOutputFixed, nil
|
||||
}
|
||||
|
||||
type SetOutputFixedArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
InstanceID uint32 `xml:"InstanceID"`
|
||||
DesiredFixed bool `xml:"DesiredFixed"`
|
||||
}
|
||||
type SetOutputFixedResponse struct {
|
||||
}
|
||||
|
||||
func (s *Service) SetOutputFixed(httpClient *http.Client, args *SetOutputFixedArgs) (*SetOutputFixedResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`SetOutputFixed`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{SetOutputFixed: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.SetOutputFixed == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling renderingcontrol.SetOutputFixed()`)
|
||||
}
|
||||
|
||||
return r.Body.SetOutputFixed, nil
|
||||
}
|
||||
|
||||
type GetHeadphoneConnectedArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
InstanceID uint32 `xml:"InstanceID"`
|
||||
}
|
||||
type GetHeadphoneConnectedResponse struct {
|
||||
CurrentHeadphoneConnected bool `xml:"CurrentHeadphoneConnected"`
|
||||
}
|
||||
|
||||
func (s *Service) GetHeadphoneConnected(httpClient *http.Client, args *GetHeadphoneConnectedArgs) (*GetHeadphoneConnectedResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`GetHeadphoneConnected`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{GetHeadphoneConnected: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.GetHeadphoneConnected == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling renderingcontrol.GetHeadphoneConnected()`)
|
||||
}
|
||||
|
||||
return r.Body.GetHeadphoneConnected, nil
|
||||
}
|
||||
|
||||
type RampToVolumeArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
InstanceID uint32 `xml:"InstanceID"`
|
||||
// Allowed Value: Master
|
||||
// Allowed Value: LF
|
||||
// Allowed Value: RF
|
||||
Channel string `xml:"Channel"`
|
||||
// Allowed Value: SLEEP_TIMER_RAMP_TYPE
|
||||
// Allowed Value: ALARM_RAMP_TYPE
|
||||
// Allowed Value: AUTOPLAY_RAMP_TYPE
|
||||
RampType string `xml:"RampType"`
|
||||
// Allowed Range: 0 -> 100 step: 1
|
||||
DesiredVolume uint16 `xml:"DesiredVolume"`
|
||||
ResetVolumeAfter bool `xml:"ResetVolumeAfter"`
|
||||
ProgramURI string `xml:"ProgramURI"`
|
||||
}
|
||||
type RampToVolumeResponse struct {
|
||||
RampTime uint32 `xml:"RampTime"`
|
||||
}
|
||||
|
||||
func (s *Service) RampToVolume(httpClient *http.Client, args *RampToVolumeArgs) (*RampToVolumeResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`RampToVolume`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{RampToVolume: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.RampToVolume == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling renderingcontrol.RampToVolume()`)
|
||||
}
|
||||
|
||||
return r.Body.RampToVolume, nil
|
||||
}
|
||||
|
||||
type RestoreVolumePriorToRampArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
InstanceID uint32 `xml:"InstanceID"`
|
||||
// Allowed Value: Master
|
||||
// Allowed Value: LF
|
||||
// Allowed Value: RF
|
||||
Channel string `xml:"Channel"`
|
||||
}
|
||||
type RestoreVolumePriorToRampResponse struct {
|
||||
}
|
||||
|
||||
func (s *Service) RestoreVolumePriorToRamp(httpClient *http.Client, args *RestoreVolumePriorToRampArgs) (*RestoreVolumePriorToRampResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`RestoreVolumePriorToRamp`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{RestoreVolumePriorToRamp: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.RestoreVolumePriorToRamp == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling renderingcontrol.RestoreVolumePriorToRamp()`)
|
||||
}
|
||||
|
||||
return r.Body.RestoreVolumePriorToRamp, nil
|
||||
}
|
||||
|
||||
type SetChannelMapArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
InstanceID uint32 `xml:"InstanceID"`
|
||||
ChannelMap string `xml:"ChannelMap"`
|
||||
}
|
||||
type SetChannelMapResponse struct {
|
||||
}
|
||||
|
||||
func (s *Service) SetChannelMap(httpClient *http.Client, args *SetChannelMapArgs) (*SetChannelMapResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`SetChannelMap`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{SetChannelMap: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.SetChannelMap == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling renderingcontrol.SetChannelMap()`)
|
||||
}
|
||||
|
||||
return r.Body.SetChannelMap, nil
|
||||
}
|
||||
|
||||
type SetRoomCalibrationXArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
InstanceID uint32 `xml:"InstanceID"`
|
||||
CalibrationID string `xml:"CalibrationID"`
|
||||
Coefficients string `xml:"Coefficients"`
|
||||
CalibrationMode string `xml:"CalibrationMode"`
|
||||
}
|
||||
type SetRoomCalibrationXResponse struct {
|
||||
}
|
||||
|
||||
func (s *Service) SetRoomCalibrationX(httpClient *http.Client, args *SetRoomCalibrationXArgs) (*SetRoomCalibrationXResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`SetRoomCalibrationX`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{SetRoomCalibrationX: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.SetRoomCalibrationX == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling renderingcontrol.SetRoomCalibrationX()`)
|
||||
}
|
||||
|
||||
return r.Body.SetRoomCalibrationX, nil
|
||||
}
|
||||
|
||||
type GetRoomCalibrationStatusArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
InstanceID uint32 `xml:"InstanceID"`
|
||||
}
|
||||
type GetRoomCalibrationStatusResponse struct {
|
||||
RoomCalibrationEnabled bool `xml:"RoomCalibrationEnabled"`
|
||||
RoomCalibrationAvailable bool `xml:"RoomCalibrationAvailable"`
|
||||
}
|
||||
|
||||
func (s *Service) GetRoomCalibrationStatus(httpClient *http.Client, args *GetRoomCalibrationStatusArgs) (*GetRoomCalibrationStatusResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`GetRoomCalibrationStatus`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{GetRoomCalibrationStatus: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.GetRoomCalibrationStatus == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling renderingcontrol.GetRoomCalibrationStatus()`)
|
||||
}
|
||||
|
||||
return r.Body.GetRoomCalibrationStatus, nil
|
||||
}
|
||||
|
||||
type SetRoomCalibrationStatusArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
InstanceID uint32 `xml:"InstanceID"`
|
||||
RoomCalibrationEnabled bool `xml:"RoomCalibrationEnabled"`
|
||||
}
|
||||
type SetRoomCalibrationStatusResponse struct {
|
||||
}
|
||||
|
||||
func (s *Service) SetRoomCalibrationStatus(httpClient *http.Client, args *SetRoomCalibrationStatusArgs) (*SetRoomCalibrationStatusResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`SetRoomCalibrationStatus`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{SetRoomCalibrationStatus: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.SetRoomCalibrationStatus == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling renderingcontrol.SetRoomCalibrationStatus()`)
|
||||
}
|
||||
|
||||
return r.Body.SetRoomCalibrationStatus, nil
|
||||
}
|
||||
+576
@@ -0,0 +1,576 @@
|
||||
package systemproperties
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/xml"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
const (
|
||||
_ServiceURN = "urn:schemas-upnp-org:service:SystemProperties:1"
|
||||
_EncodingSchema = "http://schemas.xmlsoap.org/soap/encoding/"
|
||||
_EnvelopeSchema = "http://schemas.xmlsoap.org/soap/envelope/"
|
||||
)
|
||||
|
||||
type Service struct {
|
||||
ControlEndpoint *url.URL
|
||||
EventEndpoint *url.URL
|
||||
}
|
||||
|
||||
func NewService(deviceUrl *url.URL) *Service {
|
||||
c, err := url.Parse(`/SystemProperties/Control`)
|
||||
if nil != err {
|
||||
panic(err)
|
||||
}
|
||||
e, err := url.Parse(`/SystemProperties/Event`)
|
||||
if nil != err {
|
||||
panic(err)
|
||||
}
|
||||
return &Service{
|
||||
ControlEndpoint: deviceUrl.ResolveReference(c),
|
||||
EventEndpoint: deviceUrl.ResolveReference(e),
|
||||
}
|
||||
}
|
||||
|
||||
type Envelope struct {
|
||||
XMLName xml.Name `xml:"s:Envelope"`
|
||||
Xmlns string `xml:"xmlns:s,attr"`
|
||||
EncodingStyle string `xml:"s:encodingStyle,attr"`
|
||||
Body Body `xml:"s:Body"`
|
||||
}
|
||||
type Body struct {
|
||||
XMLName xml.Name `xml:"s:Body"`
|
||||
SetString *SetStringArgs `xml:"u:SetString,omitempty"`
|
||||
GetString *GetStringArgs `xml:"u:GetString,omitempty"`
|
||||
Remove *RemoveArgs `xml:"u:Remove,omitempty"`
|
||||
GetWebCode *GetWebCodeArgs `xml:"u:GetWebCode,omitempty"`
|
||||
ProvisionCredentialedTrialAccountX *ProvisionCredentialedTrialAccountXArgs `xml:"u:ProvisionCredentialedTrialAccountX,omitempty"`
|
||||
AddAccountX *AddAccountXArgs `xml:"u:AddAccountX,omitempty"`
|
||||
AddOAuthAccountX *AddOAuthAccountXArgs `xml:"u:AddOAuthAccountX,omitempty"`
|
||||
RemoveAccount *RemoveAccountArgs `xml:"u:RemoveAccount,omitempty"`
|
||||
EditAccountPasswordX *EditAccountPasswordXArgs `xml:"u:EditAccountPasswordX,omitempty"`
|
||||
SetAccountNicknameX *SetAccountNicknameXArgs `xml:"u:SetAccountNicknameX,omitempty"`
|
||||
RefreshAccountCredentialsX *RefreshAccountCredentialsXArgs `xml:"u:RefreshAccountCredentialsX,omitempty"`
|
||||
EditAccountMd *EditAccountMdArgs `xml:"u:EditAccountMd,omitempty"`
|
||||
DoPostUpdateTasks *DoPostUpdateTasksArgs `xml:"u:DoPostUpdateTasks,omitempty"`
|
||||
ResetThirdPartyCredentials *ResetThirdPartyCredentialsArgs `xml:"u:ResetThirdPartyCredentials,omitempty"`
|
||||
EnableRDM *EnableRDMArgs `xml:"u:EnableRDM,omitempty"`
|
||||
GetRDM *GetRDMArgs `xml:"u:GetRDM,omitempty"`
|
||||
ReplaceAccountX *ReplaceAccountXArgs `xml:"u:ReplaceAccountX,omitempty"`
|
||||
}
|
||||
type EnvelopeResponse struct {
|
||||
XMLName xml.Name `xml:"Envelope"`
|
||||
Xmlns string `xml:"xmlns:s,attr"`
|
||||
EncodingStyle string `xml:"encodingStyle,attr"`
|
||||
Body BodyResponse `xml:"Body"`
|
||||
}
|
||||
type BodyResponse struct {
|
||||
XMLName xml.Name `xml:"Body"`
|
||||
SetString *SetStringResponse `xml:"SetStringResponse,omitempty"`
|
||||
GetString *GetStringResponse `xml:"GetStringResponse,omitempty"`
|
||||
Remove *RemoveResponse `xml:"RemoveResponse,omitempty"`
|
||||
GetWebCode *GetWebCodeResponse `xml:"GetWebCodeResponse,omitempty"`
|
||||
ProvisionCredentialedTrialAccountX *ProvisionCredentialedTrialAccountXResponse `xml:"ProvisionCredentialedTrialAccountXResponse,omitempty"`
|
||||
AddAccountX *AddAccountXResponse `xml:"AddAccountXResponse,omitempty"`
|
||||
AddOAuthAccountX *AddOAuthAccountXResponse `xml:"AddOAuthAccountXResponse,omitempty"`
|
||||
RemoveAccount *RemoveAccountResponse `xml:"RemoveAccountResponse,omitempty"`
|
||||
EditAccountPasswordX *EditAccountPasswordXResponse `xml:"EditAccountPasswordXResponse,omitempty"`
|
||||
SetAccountNicknameX *SetAccountNicknameXResponse `xml:"SetAccountNicknameXResponse,omitempty"`
|
||||
RefreshAccountCredentialsX *RefreshAccountCredentialsXResponse `xml:"RefreshAccountCredentialsXResponse,omitempty"`
|
||||
EditAccountMd *EditAccountMdResponse `xml:"EditAccountMdResponse,omitempty"`
|
||||
DoPostUpdateTasks *DoPostUpdateTasksResponse `xml:"DoPostUpdateTasksResponse,omitempty"`
|
||||
ResetThirdPartyCredentials *ResetThirdPartyCredentialsResponse `xml:"ResetThirdPartyCredentialsResponse,omitempty"`
|
||||
EnableRDM *EnableRDMResponse `xml:"EnableRDMResponse,omitempty"`
|
||||
GetRDM *GetRDMResponse `xml:"GetRDMResponse,omitempty"`
|
||||
ReplaceAccountX *ReplaceAccountXResponse `xml:"ReplaceAccountXResponse,omitempty"`
|
||||
}
|
||||
|
||||
func (s *Service) exec(actionName string, httpClient *http.Client, envelope *Envelope) (*EnvelopeResponse, error) {
|
||||
marshaled, err := xml.Marshal(envelope)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
postBody := []byte(`<?xml version="1.0"?>`)
|
||||
postBody = append(postBody, marshaled...)
|
||||
req, err := http.NewRequest(`POST`, s.ControlEndpoint.String(), bytes.NewBuffer(postBody))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set(`Content-Type`, `text/xml; charset="utf-8"`)
|
||||
req.Header.Set(`SOAPAction`, _ServiceURN+`#`+actionName)
|
||||
res, err := httpClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
responseBody, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var envelopeResponse EnvelopeResponse
|
||||
err = xml.Unmarshal(responseBody, &envelopeResponse)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &envelopeResponse, nil
|
||||
}
|
||||
|
||||
type SetStringArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
VariableName string `xml:"VariableName"`
|
||||
StringValue string `xml:"StringValue"`
|
||||
}
|
||||
type SetStringResponse struct {
|
||||
}
|
||||
|
||||
func (s *Service) SetString(httpClient *http.Client, args *SetStringArgs) (*SetStringResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`SetString`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{SetString: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.SetString == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling systemproperties.SetString()`)
|
||||
}
|
||||
|
||||
return r.Body.SetString, nil
|
||||
}
|
||||
|
||||
type GetStringArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
VariableName string `xml:"VariableName"`
|
||||
}
|
||||
type GetStringResponse struct {
|
||||
StringValue string `xml:"StringValue"`
|
||||
}
|
||||
|
||||
func (s *Service) GetString(httpClient *http.Client, args *GetStringArgs) (*GetStringResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`GetString`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{GetString: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.GetString == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling systemproperties.GetString()`)
|
||||
}
|
||||
|
||||
return r.Body.GetString, nil
|
||||
}
|
||||
|
||||
type RemoveArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
VariableName string `xml:"VariableName"`
|
||||
}
|
||||
type RemoveResponse struct {
|
||||
}
|
||||
|
||||
func (s *Service) Remove(httpClient *http.Client, args *RemoveArgs) (*RemoveResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`Remove`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{Remove: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.Remove == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling systemproperties.Remove()`)
|
||||
}
|
||||
|
||||
return r.Body.Remove, nil
|
||||
}
|
||||
|
||||
type GetWebCodeArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
AccountType uint32 `xml:"AccountType"`
|
||||
}
|
||||
type GetWebCodeResponse struct {
|
||||
WebCode string `xml:"WebCode"`
|
||||
}
|
||||
|
||||
func (s *Service) GetWebCode(httpClient *http.Client, args *GetWebCodeArgs) (*GetWebCodeResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`GetWebCode`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{GetWebCode: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.GetWebCode == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling systemproperties.GetWebCode()`)
|
||||
}
|
||||
|
||||
return r.Body.GetWebCode, nil
|
||||
}
|
||||
|
||||
type ProvisionCredentialedTrialAccountXArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
AccountType uint32 `xml:"AccountType"`
|
||||
AccountID string `xml:"AccountID"`
|
||||
AccountPassword string `xml:"AccountPassword"`
|
||||
}
|
||||
type ProvisionCredentialedTrialAccountXResponse struct {
|
||||
IsExpired bool `xml:"IsExpired"`
|
||||
AccountUDN string `xml:"AccountUDN"`
|
||||
}
|
||||
|
||||
func (s *Service) ProvisionCredentialedTrialAccountX(httpClient *http.Client, args *ProvisionCredentialedTrialAccountXArgs) (*ProvisionCredentialedTrialAccountXResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`ProvisionCredentialedTrialAccountX`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{ProvisionCredentialedTrialAccountX: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.ProvisionCredentialedTrialAccountX == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling systemproperties.ProvisionCredentialedTrialAccountX()`)
|
||||
}
|
||||
|
||||
return r.Body.ProvisionCredentialedTrialAccountX, nil
|
||||
}
|
||||
|
||||
type AddAccountXArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
AccountType uint32 `xml:"AccountType"`
|
||||
AccountID string `xml:"AccountID"`
|
||||
AccountPassword string `xml:"AccountPassword"`
|
||||
}
|
||||
type AddAccountXResponse struct {
|
||||
AccountUDN string `xml:"AccountUDN"`
|
||||
}
|
||||
|
||||
func (s *Service) AddAccountX(httpClient *http.Client, args *AddAccountXArgs) (*AddAccountXResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`AddAccountX`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{AddAccountX: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.AddAccountX == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling systemproperties.AddAccountX()`)
|
||||
}
|
||||
|
||||
return r.Body.AddAccountX, nil
|
||||
}
|
||||
|
||||
type AddOAuthAccountXArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
AccountType uint32 `xml:"AccountType"`
|
||||
AccountToken string `xml:"AccountToken"`
|
||||
AccountKey string `xml:"AccountKey"`
|
||||
OAuthDeviceID string `xml:"OAuthDeviceID"`
|
||||
AuthorizationCode string `xml:"AuthorizationCode"`
|
||||
RedirectURI string `xml:"RedirectURI"`
|
||||
UserIdHashCode string `xml:"UserIdHashCode"`
|
||||
AccountTier uint32 `xml:"AccountTier"`
|
||||
}
|
||||
type AddOAuthAccountXResponse struct {
|
||||
AccountUDN string `xml:"AccountUDN"`
|
||||
AccountNickname string `xml:"AccountNickname"`
|
||||
}
|
||||
|
||||
func (s *Service) AddOAuthAccountX(httpClient *http.Client, args *AddOAuthAccountXArgs) (*AddOAuthAccountXResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`AddOAuthAccountX`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{AddOAuthAccountX: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.AddOAuthAccountX == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling systemproperties.AddOAuthAccountX()`)
|
||||
}
|
||||
|
||||
return r.Body.AddOAuthAccountX, nil
|
||||
}
|
||||
|
||||
type RemoveAccountArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
AccountType uint32 `xml:"AccountType"`
|
||||
AccountID string `xml:"AccountID"`
|
||||
}
|
||||
type RemoveAccountResponse struct {
|
||||
}
|
||||
|
||||
func (s *Service) RemoveAccount(httpClient *http.Client, args *RemoveAccountArgs) (*RemoveAccountResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`RemoveAccount`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{RemoveAccount: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.RemoveAccount == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling systemproperties.RemoveAccount()`)
|
||||
}
|
||||
|
||||
return r.Body.RemoveAccount, nil
|
||||
}
|
||||
|
||||
type EditAccountPasswordXArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
AccountType uint32 `xml:"AccountType"`
|
||||
AccountID string `xml:"AccountID"`
|
||||
NewAccountPassword string `xml:"NewAccountPassword"`
|
||||
}
|
||||
type EditAccountPasswordXResponse struct {
|
||||
}
|
||||
|
||||
func (s *Service) EditAccountPasswordX(httpClient *http.Client, args *EditAccountPasswordXArgs) (*EditAccountPasswordXResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`EditAccountPasswordX`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{EditAccountPasswordX: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.EditAccountPasswordX == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling systemproperties.EditAccountPasswordX()`)
|
||||
}
|
||||
|
||||
return r.Body.EditAccountPasswordX, nil
|
||||
}
|
||||
|
||||
type SetAccountNicknameXArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
AccountUDN string `xml:"AccountUDN"`
|
||||
AccountNickname string `xml:"AccountNickname"`
|
||||
}
|
||||
type SetAccountNicknameXResponse struct {
|
||||
}
|
||||
|
||||
func (s *Service) SetAccountNicknameX(httpClient *http.Client, args *SetAccountNicknameXArgs) (*SetAccountNicknameXResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`SetAccountNicknameX`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{SetAccountNicknameX: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.SetAccountNicknameX == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling systemproperties.SetAccountNicknameX()`)
|
||||
}
|
||||
|
||||
return r.Body.SetAccountNicknameX, nil
|
||||
}
|
||||
|
||||
type RefreshAccountCredentialsXArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
AccountType uint32 `xml:"AccountType"`
|
||||
AccountUID uint32 `xml:"AccountUID"`
|
||||
AccountToken string `xml:"AccountToken"`
|
||||
AccountKey string `xml:"AccountKey"`
|
||||
}
|
||||
type RefreshAccountCredentialsXResponse struct {
|
||||
}
|
||||
|
||||
func (s *Service) RefreshAccountCredentialsX(httpClient *http.Client, args *RefreshAccountCredentialsXArgs) (*RefreshAccountCredentialsXResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`RefreshAccountCredentialsX`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{RefreshAccountCredentialsX: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.RefreshAccountCredentialsX == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling systemproperties.RefreshAccountCredentialsX()`)
|
||||
}
|
||||
|
||||
return r.Body.RefreshAccountCredentialsX, nil
|
||||
}
|
||||
|
||||
type EditAccountMdArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
AccountType uint32 `xml:"AccountType"`
|
||||
AccountID string `xml:"AccountID"`
|
||||
NewAccountMd string `xml:"NewAccountMd"`
|
||||
}
|
||||
type EditAccountMdResponse struct {
|
||||
}
|
||||
|
||||
func (s *Service) EditAccountMd(httpClient *http.Client, args *EditAccountMdArgs) (*EditAccountMdResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`EditAccountMd`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{EditAccountMd: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.EditAccountMd == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling systemproperties.EditAccountMd()`)
|
||||
}
|
||||
|
||||
return r.Body.EditAccountMd, nil
|
||||
}
|
||||
|
||||
type DoPostUpdateTasksArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
}
|
||||
type DoPostUpdateTasksResponse struct {
|
||||
}
|
||||
|
||||
func (s *Service) DoPostUpdateTasks(httpClient *http.Client, args *DoPostUpdateTasksArgs) (*DoPostUpdateTasksResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`DoPostUpdateTasks`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{DoPostUpdateTasks: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.DoPostUpdateTasks == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling systemproperties.DoPostUpdateTasks()`)
|
||||
}
|
||||
|
||||
return r.Body.DoPostUpdateTasks, nil
|
||||
}
|
||||
|
||||
type ResetThirdPartyCredentialsArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
}
|
||||
type ResetThirdPartyCredentialsResponse struct {
|
||||
}
|
||||
|
||||
func (s *Service) ResetThirdPartyCredentials(httpClient *http.Client, args *ResetThirdPartyCredentialsArgs) (*ResetThirdPartyCredentialsResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`ResetThirdPartyCredentials`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{ResetThirdPartyCredentials: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.ResetThirdPartyCredentials == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling systemproperties.ResetThirdPartyCredentials()`)
|
||||
}
|
||||
|
||||
return r.Body.ResetThirdPartyCredentials, nil
|
||||
}
|
||||
|
||||
type EnableRDMArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
RDMValue bool `xml:"RDMValue"`
|
||||
}
|
||||
type EnableRDMResponse struct {
|
||||
}
|
||||
|
||||
func (s *Service) EnableRDM(httpClient *http.Client, args *EnableRDMArgs) (*EnableRDMResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`EnableRDM`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{EnableRDM: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.EnableRDM == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling systemproperties.EnableRDM()`)
|
||||
}
|
||||
|
||||
return r.Body.EnableRDM, nil
|
||||
}
|
||||
|
||||
type GetRDMArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
}
|
||||
type GetRDMResponse struct {
|
||||
RDMValue bool `xml:"RDMValue"`
|
||||
}
|
||||
|
||||
func (s *Service) GetRDM(httpClient *http.Client, args *GetRDMArgs) (*GetRDMResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`GetRDM`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{GetRDM: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.GetRDM == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling systemproperties.GetRDM()`)
|
||||
}
|
||||
|
||||
return r.Body.GetRDM, nil
|
||||
}
|
||||
|
||||
type ReplaceAccountXArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
AccountUDN string `xml:"AccountUDN"`
|
||||
NewAccountID string `xml:"NewAccountID"`
|
||||
NewAccountPassword string `xml:"NewAccountPassword"`
|
||||
AccountToken string `xml:"AccountToken"`
|
||||
AccountKey string `xml:"AccountKey"`
|
||||
OAuthDeviceID string `xml:"OAuthDeviceID"`
|
||||
}
|
||||
type ReplaceAccountXResponse struct {
|
||||
NewAccountUDN string `xml:"NewAccountUDN"`
|
||||
}
|
||||
|
||||
func (s *Service) ReplaceAccountX(httpClient *http.Client, args *ReplaceAccountXArgs) (*ReplaceAccountXResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`ReplaceAccountX`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{ReplaceAccountX: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.ReplaceAccountX == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling systemproperties.ReplaceAccountX()`)
|
||||
}
|
||||
|
||||
return r.Body.ReplaceAccountX, nil
|
||||
}
|
||||
+306
@@ -0,0 +1,306 @@
|
||||
package virtuallinein
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/xml"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
const (
|
||||
_ServiceURN = "urn:schemas-upnp-org:service:VirtualLineIn:1"
|
||||
_EncodingSchema = "http://schemas.xmlsoap.org/soap/encoding/"
|
||||
_EnvelopeSchema = "http://schemas.xmlsoap.org/soap/envelope/"
|
||||
)
|
||||
|
||||
type Service struct {
|
||||
ControlEndpoint *url.URL
|
||||
EventEndpoint *url.URL
|
||||
}
|
||||
|
||||
func NewService(deviceUrl *url.URL) *Service {
|
||||
c, err := url.Parse(`/MediaRenderer/VirtualLineIn/Control`)
|
||||
if nil != err {
|
||||
panic(err)
|
||||
}
|
||||
e, err := url.Parse(`/MediaRenderer/VirtualLineIn/Event`)
|
||||
if nil != err {
|
||||
panic(err)
|
||||
}
|
||||
return &Service{
|
||||
ControlEndpoint: deviceUrl.ResolveReference(c),
|
||||
EventEndpoint: deviceUrl.ResolveReference(e),
|
||||
}
|
||||
}
|
||||
|
||||
type Envelope struct {
|
||||
XMLName xml.Name `xml:"s:Envelope"`
|
||||
Xmlns string `xml:"xmlns:s,attr"`
|
||||
EncodingStyle string `xml:"s:encodingStyle,attr"`
|
||||
Body Body `xml:"s:Body"`
|
||||
}
|
||||
type Body struct {
|
||||
XMLName xml.Name `xml:"s:Body"`
|
||||
StartTransmission *StartTransmissionArgs `xml:"u:StartTransmission,omitempty"`
|
||||
StopTransmission *StopTransmissionArgs `xml:"u:StopTransmission,omitempty"`
|
||||
Play *PlayArgs `xml:"u:Play,omitempty"`
|
||||
Pause *PauseArgs `xml:"u:Pause,omitempty"`
|
||||
Next *NextArgs `xml:"u:Next,omitempty"`
|
||||
Previous *PreviousArgs `xml:"u:Previous,omitempty"`
|
||||
Stop *StopArgs `xml:"u:Stop,omitempty"`
|
||||
SetVolume *SetVolumeArgs `xml:"u:SetVolume,omitempty"`
|
||||
}
|
||||
type EnvelopeResponse struct {
|
||||
XMLName xml.Name `xml:"Envelope"`
|
||||
Xmlns string `xml:"xmlns:s,attr"`
|
||||
EncodingStyle string `xml:"encodingStyle,attr"`
|
||||
Body BodyResponse `xml:"Body"`
|
||||
}
|
||||
type BodyResponse struct {
|
||||
XMLName xml.Name `xml:"Body"`
|
||||
StartTransmission *StartTransmissionResponse `xml:"StartTransmissionResponse,omitempty"`
|
||||
StopTransmission *StopTransmissionResponse `xml:"StopTransmissionResponse,omitempty"`
|
||||
Play *PlayResponse `xml:"PlayResponse,omitempty"`
|
||||
Pause *PauseResponse `xml:"PauseResponse,omitempty"`
|
||||
Next *NextResponse `xml:"NextResponse,omitempty"`
|
||||
Previous *PreviousResponse `xml:"PreviousResponse,omitempty"`
|
||||
Stop *StopResponse `xml:"StopResponse,omitempty"`
|
||||
SetVolume *SetVolumeResponse `xml:"SetVolumeResponse,omitempty"`
|
||||
}
|
||||
|
||||
func (s *Service) exec(actionName string, httpClient *http.Client, envelope *Envelope) (*EnvelopeResponse, error) {
|
||||
marshaled, err := xml.Marshal(envelope)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
postBody := []byte(`<?xml version="1.0"?>`)
|
||||
postBody = append(postBody, marshaled...)
|
||||
req, err := http.NewRequest(`POST`, s.ControlEndpoint.String(), bytes.NewBuffer(postBody))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set(`Content-Type`, `text/xml; charset="utf-8"`)
|
||||
req.Header.Set(`SOAPAction`, _ServiceURN+`#`+actionName)
|
||||
res, err := httpClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
responseBody, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var envelopeResponse EnvelopeResponse
|
||||
err = xml.Unmarshal(responseBody, &envelopeResponse)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &envelopeResponse, nil
|
||||
}
|
||||
|
||||
type StartTransmissionArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
InstanceID uint32 `xml:"InstanceID"`
|
||||
CoordinatorID string `xml:"CoordinatorID"`
|
||||
}
|
||||
type StartTransmissionResponse struct {
|
||||
CurrentTransportSettings string `xml:"CurrentTransportSettings"`
|
||||
}
|
||||
|
||||
func (s *Service) StartTransmission(httpClient *http.Client, args *StartTransmissionArgs) (*StartTransmissionResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`StartTransmission`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{StartTransmission: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.StartTransmission == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling virtuallinein.StartTransmission()`)
|
||||
}
|
||||
|
||||
return r.Body.StartTransmission, nil
|
||||
}
|
||||
|
||||
type StopTransmissionArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
InstanceID uint32 `xml:"InstanceID"`
|
||||
CoordinatorID string `xml:"CoordinatorID"`
|
||||
}
|
||||
type StopTransmissionResponse struct {
|
||||
}
|
||||
|
||||
func (s *Service) StopTransmission(httpClient *http.Client, args *StopTransmissionArgs) (*StopTransmissionResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`StopTransmission`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{StopTransmission: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.StopTransmission == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling virtuallinein.StopTransmission()`)
|
||||
}
|
||||
|
||||
return r.Body.StopTransmission, nil
|
||||
}
|
||||
|
||||
type PlayArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
InstanceID uint32 `xml:"InstanceID"`
|
||||
Speed string `xml:"Speed"`
|
||||
}
|
||||
type PlayResponse struct {
|
||||
}
|
||||
|
||||
func (s *Service) Play(httpClient *http.Client, args *PlayArgs) (*PlayResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`Play`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{Play: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.Play == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling virtuallinein.Play()`)
|
||||
}
|
||||
|
||||
return r.Body.Play, nil
|
||||
}
|
||||
|
||||
type PauseArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
InstanceID uint32 `xml:"InstanceID"`
|
||||
}
|
||||
type PauseResponse struct {
|
||||
}
|
||||
|
||||
func (s *Service) Pause(httpClient *http.Client, args *PauseArgs) (*PauseResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`Pause`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{Pause: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.Pause == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling virtuallinein.Pause()`)
|
||||
}
|
||||
|
||||
return r.Body.Pause, nil
|
||||
}
|
||||
|
||||
type NextArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
InstanceID uint32 `xml:"InstanceID"`
|
||||
}
|
||||
type NextResponse struct {
|
||||
}
|
||||
|
||||
func (s *Service) Next(httpClient *http.Client, args *NextArgs) (*NextResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`Next`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{Next: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.Next == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling virtuallinein.Next()`)
|
||||
}
|
||||
|
||||
return r.Body.Next, nil
|
||||
}
|
||||
|
||||
type PreviousArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
InstanceID uint32 `xml:"InstanceID"`
|
||||
}
|
||||
type PreviousResponse struct {
|
||||
}
|
||||
|
||||
func (s *Service) Previous(httpClient *http.Client, args *PreviousArgs) (*PreviousResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`Previous`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{Previous: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.Previous == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling virtuallinein.Previous()`)
|
||||
}
|
||||
|
||||
return r.Body.Previous, nil
|
||||
}
|
||||
|
||||
type StopArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
InstanceID uint32 `xml:"InstanceID"`
|
||||
}
|
||||
type StopResponse struct {
|
||||
}
|
||||
|
||||
func (s *Service) Stop(httpClient *http.Client, args *StopArgs) (*StopResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`Stop`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{Stop: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.Stop == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling virtuallinein.Stop()`)
|
||||
}
|
||||
|
||||
return r.Body.Stop, nil
|
||||
}
|
||||
|
||||
type SetVolumeArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
InstanceID uint32 `xml:"InstanceID"`
|
||||
DesiredVolume uint16 `xml:"DesiredVolume"`
|
||||
}
|
||||
type SetVolumeResponse struct {
|
||||
}
|
||||
|
||||
func (s *Service) SetVolume(httpClient *http.Client, args *SetVolumeArgs) (*SetVolumeResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`SetVolume`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{SetVolume: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.SetVolume == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling virtuallinein.SetVolume()`)
|
||||
}
|
||||
|
||||
return r.Body.SetVolume, nil
|
||||
}
|
||||
+318
@@ -0,0 +1,318 @@
|
||||
package zonegrouptopology
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/xml"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
const (
|
||||
_ServiceURN = "urn:schemas-upnp-org:service:ZoneGroupTopology:1"
|
||||
_EncodingSchema = "http://schemas.xmlsoap.org/soap/encoding/"
|
||||
_EnvelopeSchema = "http://schemas.xmlsoap.org/soap/envelope/"
|
||||
)
|
||||
|
||||
type Service struct {
|
||||
ControlEndpoint *url.URL
|
||||
EventEndpoint *url.URL
|
||||
}
|
||||
|
||||
func NewService(deviceUrl *url.URL) *Service {
|
||||
c, err := url.Parse(`/ZoneGroupTopology/Control`)
|
||||
if nil != err {
|
||||
panic(err)
|
||||
}
|
||||
e, err := url.Parse(`/ZoneGroupTopology/Event`)
|
||||
if nil != err {
|
||||
panic(err)
|
||||
}
|
||||
return &Service{
|
||||
ControlEndpoint: deviceUrl.ResolveReference(c),
|
||||
EventEndpoint: deviceUrl.ResolveReference(e),
|
||||
}
|
||||
}
|
||||
|
||||
type Envelope struct {
|
||||
XMLName xml.Name `xml:"s:Envelope"`
|
||||
Xmlns string `xml:"xmlns:s,attr"`
|
||||
EncodingStyle string `xml:"s:encodingStyle,attr"`
|
||||
Body Body `xml:"s:Body"`
|
||||
}
|
||||
type Body struct {
|
||||
XMLName xml.Name `xml:"s:Body"`
|
||||
CheckForUpdate *CheckForUpdateArgs `xml:"u:CheckForUpdate,omitempty"`
|
||||
BeginSoftwareUpdate *BeginSoftwareUpdateArgs `xml:"u:BeginSoftwareUpdate,omitempty"`
|
||||
ReportUnresponsiveDevice *ReportUnresponsiveDeviceArgs `xml:"u:ReportUnresponsiveDevice,omitempty"`
|
||||
ReportAlarmStartedRunning *ReportAlarmStartedRunningArgs `xml:"u:ReportAlarmStartedRunning,omitempty"`
|
||||
SubmitDiagnostics *SubmitDiagnosticsArgs `xml:"u:SubmitDiagnostics,omitempty"`
|
||||
RegisterMobileDevice *RegisterMobileDeviceArgs `xml:"u:RegisterMobileDevice,omitempty"`
|
||||
GetZoneGroupAttributes *GetZoneGroupAttributesArgs `xml:"u:GetZoneGroupAttributes,omitempty"`
|
||||
GetZoneGroupState *GetZoneGroupStateArgs `xml:"u:GetZoneGroupState,omitempty"`
|
||||
}
|
||||
type EnvelopeResponse struct {
|
||||
XMLName xml.Name `xml:"Envelope"`
|
||||
Xmlns string `xml:"xmlns:s,attr"`
|
||||
EncodingStyle string `xml:"encodingStyle,attr"`
|
||||
Body BodyResponse `xml:"Body"`
|
||||
}
|
||||
type BodyResponse struct {
|
||||
XMLName xml.Name `xml:"Body"`
|
||||
CheckForUpdate *CheckForUpdateResponse `xml:"CheckForUpdateResponse,omitempty"`
|
||||
BeginSoftwareUpdate *BeginSoftwareUpdateResponse `xml:"BeginSoftwareUpdateResponse,omitempty"`
|
||||
ReportUnresponsiveDevice *ReportUnresponsiveDeviceResponse `xml:"ReportUnresponsiveDeviceResponse,omitempty"`
|
||||
ReportAlarmStartedRunning *ReportAlarmStartedRunningResponse `xml:"ReportAlarmStartedRunningResponse,omitempty"`
|
||||
SubmitDiagnostics *SubmitDiagnosticsResponse `xml:"SubmitDiagnosticsResponse,omitempty"`
|
||||
RegisterMobileDevice *RegisterMobileDeviceResponse `xml:"RegisterMobileDeviceResponse,omitempty"`
|
||||
GetZoneGroupAttributes *GetZoneGroupAttributesResponse `xml:"GetZoneGroupAttributesResponse,omitempty"`
|
||||
GetZoneGroupState *GetZoneGroupStateResponse `xml:"GetZoneGroupStateResponse,omitempty"`
|
||||
}
|
||||
|
||||
func (s *Service) exec(actionName string, httpClient *http.Client, envelope *Envelope) (*EnvelopeResponse, error) {
|
||||
marshaled, err := xml.Marshal(envelope)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
postBody := []byte(`<?xml version="1.0"?>`)
|
||||
postBody = append(postBody, marshaled...)
|
||||
req, err := http.NewRequest(`POST`, s.ControlEndpoint.String(), bytes.NewBuffer(postBody))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set(`Content-Type`, `text/xml; charset="utf-8"`)
|
||||
req.Header.Set(`SOAPAction`, _ServiceURN+`#`+actionName)
|
||||
res, err := httpClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
responseBody, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var envelopeResponse EnvelopeResponse
|
||||
err = xml.Unmarshal(responseBody, &envelopeResponse)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &envelopeResponse, nil
|
||||
}
|
||||
|
||||
type CheckForUpdateArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
// Allowed Value: All
|
||||
// Allowed Value: Software
|
||||
UpdateType string `xml:"UpdateType"`
|
||||
CachedOnly bool `xml:"CachedOnly"`
|
||||
Version string `xml:"Version"`
|
||||
}
|
||||
type CheckForUpdateResponse struct {
|
||||
UpdateItem string `xml:"UpdateItem"`
|
||||
}
|
||||
|
||||
func (s *Service) CheckForUpdate(httpClient *http.Client, args *CheckForUpdateArgs) (*CheckForUpdateResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`CheckForUpdate`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{CheckForUpdate: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.CheckForUpdate == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling zonegrouptopology.CheckForUpdate()`)
|
||||
}
|
||||
|
||||
return r.Body.CheckForUpdate, nil
|
||||
}
|
||||
|
||||
type BeginSoftwareUpdateArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
UpdateURL string `xml:"UpdateURL"`
|
||||
Flags uint32 `xml:"Flags"`
|
||||
ExtraOptions string `xml:"ExtraOptions"`
|
||||
}
|
||||
type BeginSoftwareUpdateResponse struct {
|
||||
}
|
||||
|
||||
func (s *Service) BeginSoftwareUpdate(httpClient *http.Client, args *BeginSoftwareUpdateArgs) (*BeginSoftwareUpdateResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`BeginSoftwareUpdate`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{BeginSoftwareUpdate: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.BeginSoftwareUpdate == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling zonegrouptopology.BeginSoftwareUpdate()`)
|
||||
}
|
||||
|
||||
return r.Body.BeginSoftwareUpdate, nil
|
||||
}
|
||||
|
||||
type ReportUnresponsiveDeviceArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
DeviceUUID string `xml:"DeviceUUID"`
|
||||
// Allowed Value: Remove
|
||||
// Allowed Value: TopologyMonitorProbe
|
||||
// Allowed Value: VerifyThenRemoveSystemwide
|
||||
DesiredAction string `xml:"DesiredAction"`
|
||||
}
|
||||
type ReportUnresponsiveDeviceResponse struct {
|
||||
}
|
||||
|
||||
func (s *Service) ReportUnresponsiveDevice(httpClient *http.Client, args *ReportUnresponsiveDeviceArgs) (*ReportUnresponsiveDeviceResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`ReportUnresponsiveDevice`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{ReportUnresponsiveDevice: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.ReportUnresponsiveDevice == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling zonegrouptopology.ReportUnresponsiveDevice()`)
|
||||
}
|
||||
|
||||
return r.Body.ReportUnresponsiveDevice, nil
|
||||
}
|
||||
|
||||
type ReportAlarmStartedRunningArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
}
|
||||
type ReportAlarmStartedRunningResponse struct {
|
||||
}
|
||||
|
||||
func (s *Service) ReportAlarmStartedRunning(httpClient *http.Client, args *ReportAlarmStartedRunningArgs) (*ReportAlarmStartedRunningResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`ReportAlarmStartedRunning`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{ReportAlarmStartedRunning: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.ReportAlarmStartedRunning == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling zonegrouptopology.ReportAlarmStartedRunning()`)
|
||||
}
|
||||
|
||||
return r.Body.ReportAlarmStartedRunning, nil
|
||||
}
|
||||
|
||||
type SubmitDiagnosticsArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
IncludeControllers bool `xml:"IncludeControllers"`
|
||||
Type string `xml:"Type"`
|
||||
}
|
||||
type SubmitDiagnosticsResponse struct {
|
||||
DiagnosticID uint32 `xml:"DiagnosticID"`
|
||||
}
|
||||
|
||||
func (s *Service) SubmitDiagnostics(httpClient *http.Client, args *SubmitDiagnosticsArgs) (*SubmitDiagnosticsResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`SubmitDiagnostics`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{SubmitDiagnostics: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.SubmitDiagnostics == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling zonegrouptopology.SubmitDiagnostics()`)
|
||||
}
|
||||
|
||||
return r.Body.SubmitDiagnostics, nil
|
||||
}
|
||||
|
||||
type RegisterMobileDeviceArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
MobileDeviceName string `xml:"MobileDeviceName"`
|
||||
MobileDeviceUDN string `xml:"MobileDeviceUDN"`
|
||||
MobileIPAndPort string `xml:"MobileIPAndPort"`
|
||||
}
|
||||
type RegisterMobileDeviceResponse struct {
|
||||
}
|
||||
|
||||
func (s *Service) RegisterMobileDevice(httpClient *http.Client, args *RegisterMobileDeviceArgs) (*RegisterMobileDeviceResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`RegisterMobileDevice`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{RegisterMobileDevice: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.RegisterMobileDevice == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling zonegrouptopology.RegisterMobileDevice()`)
|
||||
}
|
||||
|
||||
return r.Body.RegisterMobileDevice, nil
|
||||
}
|
||||
|
||||
type GetZoneGroupAttributesArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
}
|
||||
type GetZoneGroupAttributesResponse struct {
|
||||
CurrentZoneGroupName string `xml:"CurrentZoneGroupName"`
|
||||
CurrentZoneGroupID string `xml:"CurrentZoneGroupID"`
|
||||
CurrentZonePlayerUUIDsInGroup string `xml:"CurrentZonePlayerUUIDsInGroup"`
|
||||
CurrentMuseHouseholdId string `xml:"CurrentMuseHouseholdId"`
|
||||
}
|
||||
|
||||
func (s *Service) GetZoneGroupAttributes(httpClient *http.Client, args *GetZoneGroupAttributesArgs) (*GetZoneGroupAttributesResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`GetZoneGroupAttributes`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{GetZoneGroupAttributes: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.GetZoneGroupAttributes == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling zonegrouptopology.GetZoneGroupAttributes()`)
|
||||
}
|
||||
|
||||
return r.Body.GetZoneGroupAttributes, nil
|
||||
}
|
||||
|
||||
type GetZoneGroupStateArgs struct {
|
||||
Xmlns string `xml:"xmlns:u,attr"`
|
||||
}
|
||||
type GetZoneGroupStateResponse struct {
|
||||
ZoneGroupState string `xml:"ZoneGroupState"`
|
||||
}
|
||||
|
||||
func (s *Service) GetZoneGroupState(httpClient *http.Client, args *GetZoneGroupStateArgs) (*GetZoneGroupStateResponse, error) {
|
||||
args.Xmlns = _ServiceURN
|
||||
r, err := s.exec(`GetZoneGroupState`, httpClient,
|
||||
&Envelope{
|
||||
EncodingStyle: _EncodingSchema,
|
||||
Xmlns: _EnvelopeSchema,
|
||||
Body: Body{GetZoneGroupState: args},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Body.GetZoneGroupState == nil {
|
||||
return nil, errors.New(`unexpected respose from service calling zonegrouptopology.GetZoneGroupState()`)
|
||||
}
|
||||
|
||||
return r.Body.GetZoneGroupState, nil
|
||||
}
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
package sonos
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
mx = 5
|
||||
st = "urn:schemas-upnp-org:device:ZonePlayer:1"
|
||||
bcastaddr = "239.255.255.250:1900"
|
||||
)
|
||||
|
||||
type Sonos struct {
|
||||
// Context Context
|
||||
listenSocket *net.UDPConn
|
||||
udpReader *bufio.Reader
|
||||
found chan *ZonePlayer
|
||||
}
|
||||
|
||||
func NewSonos() (*Sonos, error) {
|
||||
conn, err := net.ListenUDP("udp", &net.UDPAddr{IP: []byte{0, 0, 0, 0}, Port: 0, Zone: ""})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s := Sonos{
|
||||
listenSocket: conn,
|
||||
udpReader: bufio.NewReader(conn),
|
||||
found: make(chan *ZonePlayer),
|
||||
}
|
||||
|
||||
return &s, nil
|
||||
}
|
||||
|
||||
func (s *Sonos) Close() {
|
||||
s.listenSocket.Close()
|
||||
}
|
||||
|
||||
func (s *Sonos) Search() (chan *ZonePlayer, error) {
|
||||
go func() {
|
||||
for {
|
||||
response, err := http.ReadResponse(s.udpReader, nil)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
location, err := url.Parse(response.Header.Get("Location"))
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
zp, err := NewZonePlayer(location)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if zp.IsCoordinator() {
|
||||
s.found <- zp
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// MX should be set to use timeout value in integer seconds
|
||||
pkt := []byte(fmt.Sprintf("M-SEARCH * HTTP/1.1\r\nHOST: %s\r\nMAN: \"ssdp:discover\"\r\nMX: %d\r\nST: %s\r\n\r\n", bcastaddr, mx, st))
|
||||
bcast, err := net.ResolveUDPAddr("udp", bcastaddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = s.listenSocket.WriteTo(pkt, bcast)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return s.found, nil
|
||||
}
|
||||
|
||||
func FindRoom(room string, timeout time.Duration) (*ZonePlayer, error) {
|
||||
son, err := NewSonos()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer son.Close()
|
||||
|
||||
found, _ := son.Search()
|
||||
to := time.After(timeout)
|
||||
for {
|
||||
select {
|
||||
case <-to:
|
||||
return nil, errors.New("timeout")
|
||||
case zp := <-found:
|
||||
if zp.RoomName() == room {
|
||||
return zp, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+107
@@ -0,0 +1,107 @@
|
||||
package sonos
|
||||
|
||||
import "encoding/xml"
|
||||
|
||||
type VanishedDevice struct {
|
||||
XMLName xml.Name `xml:"VanishedDevice"`
|
||||
UUID string `xml:"UUID"`
|
||||
Location string `xml:"Location"`
|
||||
ZoneName string `xml:"ZoneName"`
|
||||
Icon string `xml:"Icon"`
|
||||
Configuration string `xml:"Configuration"`
|
||||
SoftwareVersion string `xml:"SoftwareVersion"`
|
||||
SWGen string `xml:"SWGen"`
|
||||
MinCompatibleVersion string `xml:"MinCompatibleVersion"`
|
||||
LegacyCompatibleVersion string `xml:"LegacyCompatibleVersion"`
|
||||
BootSeq string `xml:"BootSeq"`
|
||||
TVConfigurationError string `xml:"TVConfigurationError"`
|
||||
HdmiCecAvailable string `xml:"HdmiCecAvailable"`
|
||||
WirelessMode string `xml:"WirelessMode"`
|
||||
WirelessLeafOnly string `xml:"WirelessLeafOnly"`
|
||||
HasConfiguredSSID string `xml:"HasConfiguredSSID"`
|
||||
ChannelFreq string `xml:"ChannelFreq"`
|
||||
BehindWifiExtender string `xml:"BehindWifiExtender"`
|
||||
WifiEnabled string `xml:"WifiEnabled"`
|
||||
Orientation string `xml:"Orientation"`
|
||||
RoomCalibrationState string `xml:"RoomCalibrationState"`
|
||||
SecureRegState string `xml:"SecureRegState"`
|
||||
VoiceConfigState string `xml:"VoiceConfigState"`
|
||||
MicEnabled string `xml:"MicEnabled"`
|
||||
AirPlayEnabled string `xml:"AirPlayEnabled"`
|
||||
IdleState string `xml:"IdleState"`
|
||||
MoreInfo string `xml:"MoreInfo"`
|
||||
}
|
||||
|
||||
type Satellite struct {
|
||||
XMLName xml.Name `xml:"Satellite"`
|
||||
UUID string `xml:"UUID"`
|
||||
Location string `xml:"Location"`
|
||||
ZoneName string `xml:"ZoneName"`
|
||||
Icon string `xml:"Icon"`
|
||||
Configuration string `xml:"Configuration"`
|
||||
SoftwareVersion string `xml:"SoftwareVersion"`
|
||||
SWGen string `xml:"SWGen"`
|
||||
MinCompatibleVersion string `xml:"MinCompatibleVersion"`
|
||||
LegacyCompatibleVersion string `xml:"LegacyCompatibleVersion"`
|
||||
BootSeq string `xml:"BootSeq"`
|
||||
TVConfigurationError string `xml:"TVConfigurationError"`
|
||||
HdmiCecAvailable string `xml:"HdmiCecAvailable"`
|
||||
WirelessMode string `xml:"WirelessMode"`
|
||||
WirelessLeafOnly string `xml:"WirelessLeafOnly"`
|
||||
HasConfiguredSSID string `xml:"HasConfiguredSSID"`
|
||||
ChannelFreq string `xml:"ChannelFreq"`
|
||||
BehindWifiExtender string `xml:"BehindWifiExtender"`
|
||||
WifiEnabled string `xml:"WifiEnabled"`
|
||||
Orientation string `xml:"Orientation"`
|
||||
RoomCalibrationState string `xml:"RoomCalibrationState"`
|
||||
SecureRegState string `xml:"SecureRegState"`
|
||||
VoiceConfigState string `xml:"VoiceConfigState"`
|
||||
MicEnabled string `xml:"MicEnabled"`
|
||||
AirPlayEnabled string `xml:"AirPlayEnabled"`
|
||||
IdleState string `xml:"IdleState"`
|
||||
MoreInfo string `xml:"MoreInfo"`
|
||||
}
|
||||
|
||||
type ZoneGroupMember struct {
|
||||
XMLName xml.Name `xml:"ZoneGroupMember"`
|
||||
UUID string `xml:"UUID"`
|
||||
Location string `xml:"Location"`
|
||||
ZoneName string `xml:"ZoneName"`
|
||||
Icon string `xml:"Icon"`
|
||||
Configuration string `xml:"Configuration"`
|
||||
SoftwareVersion string `xml:"SoftwareVersion"`
|
||||
SWGen string `xml:"SWGen"`
|
||||
MinCompatibleVersion string `xml:"MinCompatibleVersion"`
|
||||
LegacyCompatibleVersion string `xml:"LegacyCompatibleVersion"`
|
||||
BootSeq string `xml:"BootSeq"`
|
||||
TVConfigurationError string `xml:"TVConfigurationError"`
|
||||
HdmiCecAvailable string `xml:"HdmiCecAvailable"`
|
||||
WirelessMode string `xml:"WirelessMode"`
|
||||
WirelessLeafOnly string `xml:"WirelessLeafOnly"`
|
||||
HasConfiguredSSID string `xml:"HasConfiguredSSID"`
|
||||
ChannelFreq string `xml:"ChannelFreq"`
|
||||
BehindWifiExtender string `xml:"BehindWifiExtender"`
|
||||
WifiEnabled string `xml:"WifiEnabled"`
|
||||
Orientation string `xml:"Orientation"`
|
||||
RoomCalibrationState string `xml:"RoomCalibrationState"`
|
||||
SecureRegState string `xml:"SecureRegState"`
|
||||
VoiceConfigState string `xml:"VoiceConfigState"`
|
||||
MicEnabled string `xml:"MicEnabled"`
|
||||
AirPlayEnabled string `xml:"AirPlayEnabled"`
|
||||
IdleState string `xml:"IdleState"`
|
||||
MoreInfo string `xml:"MoreInfo"`
|
||||
Satellite []Satellite `xml:"Satellite>Satellite"`
|
||||
VanishedDevice []VanishedDevice `xml:"VanishedDevices>VanishedDevice"`
|
||||
}
|
||||
|
||||
type ZoneGroup struct {
|
||||
XMLName xml.Name `xml:"ZoneGroup"`
|
||||
Coordinator string `xml:"Coordinator,attr"`
|
||||
ID string `xml:"ID,attr"`
|
||||
ZoneGroupMember []ZoneGroupMember `xml:"ZoneGroupMember"`
|
||||
}
|
||||
|
||||
type ZoneGroupState struct {
|
||||
XMLName xml.Name `xml:"ZoneGroupState"`
|
||||
ZoneGroups []ZoneGroup `xml:"ZoneGroups>ZoneGroup"`
|
||||
}
|
||||
+236
@@ -0,0 +1,236 @@
|
||||
package sonos
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
avt "github.com/szatmary/sonos/AVTransport"
|
||||
clk "github.com/szatmary/sonos/AlarmClock"
|
||||
con "github.com/szatmary/sonos/ConnectionManager"
|
||||
dir "github.com/szatmary/sonos/ContentDirectory"
|
||||
dev "github.com/szatmary/sonos/DeviceProperties"
|
||||
gmn "github.com/szatmary/sonos/GroupManagement"
|
||||
rcg "github.com/szatmary/sonos/GroupRenderingControl"
|
||||
mus "github.com/szatmary/sonos/MusicServices"
|
||||
ply "github.com/szatmary/sonos/QPlay"
|
||||
que "github.com/szatmary/sonos/Queue"
|
||||
ren "github.com/szatmary/sonos/RenderingControl"
|
||||
sys "github.com/szatmary/sonos/SystemProperties"
|
||||
vli "github.com/szatmary/sonos/VirtualLineIn"
|
||||
zgt "github.com/szatmary/sonos/ZoneGroupTopology"
|
||||
)
|
||||
|
||||
type SpecVersion struct {
|
||||
XMLName xml.Name `xml:"specVersion"`
|
||||
Major int `xml:"major"`
|
||||
Minor int `xml:"minor"`
|
||||
}
|
||||
|
||||
type Service struct {
|
||||
XMLName xml.Name `xml:"service"`
|
||||
ServiceType string `xml:"serviceType"`
|
||||
ServiceId string `xml:"serviceId"`
|
||||
ControlURL string `xml:"controlURL"`
|
||||
EventSubURL string `xml:"eventSubURL"`
|
||||
SCPDURL string `xml:"SCPDURL"`
|
||||
}
|
||||
|
||||
type Icon struct {
|
||||
XMLName xml.Name `xml:"icon"`
|
||||
Id string `xml:"id"`
|
||||
Mimetype string `xml:"mimetype"`
|
||||
Width int `xml:"width"`
|
||||
Height int `xml:"height"`
|
||||
Depth int `xml:"depth"`
|
||||
Url url.URL `xml:"url"`
|
||||
}
|
||||
|
||||
type Device struct {
|
||||
XMLName xml.Name `xml:"device"`
|
||||
DeviceType string `xml:"deviceType"`
|
||||
FriendlyName string `xml:"friendlyName"`
|
||||
Manufacturer string `xml:"manufacturer"`
|
||||
ManufacturerURL string `xml:"manufacturerURL"`
|
||||
ModelNumber string `xml:"modelNumber"`
|
||||
ModelDescription string `xml:"modelDescription"`
|
||||
ModelName string `xml:"modelName"`
|
||||
ModelURL string `xml:"modelURL"`
|
||||
SoftwareVersion string `xml:"softwareVersion"`
|
||||
SwGen string `xml:"swGen"`
|
||||
HardwareVersion string `xml:"hardwareVersion"`
|
||||
SerialNum string `xml:"serialNum"`
|
||||
MACAddress string `xml:"MACAddress"`
|
||||
UDN string `xml:"UDN"`
|
||||
Icons []Icon `xml:"iconList>icon"`
|
||||
MinCompatibleVersion string `xml:"minCompatibleVersion"`
|
||||
LegacyCompatibleVersion string `xml:"legacyCompatibleVersion"`
|
||||
ApiVersion string `xml:"apiVersion"`
|
||||
MinApiVersion string `xml:"minApiVersion"`
|
||||
DisplayVersion string `xml:"displayVersion"`
|
||||
ExtraVersion string `xml:"extraVersion"`
|
||||
RoomName string `xml:"roomName"`
|
||||
DisplayName string `xml:"displayName"`
|
||||
ZoneType int `xml:"zoneType"`
|
||||
Feature1 string `xml:"feature1"`
|
||||
Feature2 string `xml:"feature2"`
|
||||
Feature3 string `xml:"feature3"`
|
||||
Seriesid string `xml:"seriesid"`
|
||||
Variant int `xml:"variant"`
|
||||
InternalSpeakerSize float32 `xml:"internalSpeakerSize"`
|
||||
BassExtension float32 `xml:"bassExtension"`
|
||||
SatGainOffset float32 `xml:"satGainOffset"`
|
||||
Memory int `xml:"memory"`
|
||||
Flash int `xml:"flash"`
|
||||
FlashRepartitioned int `xml:"flashRepartitioned"`
|
||||
AmpOnTime int `xml:"ampOnTime"`
|
||||
RetailMode int `xml:"retailMode"`
|
||||
Services []Service `xml:"serviceList>service"`
|
||||
Devices []Device `xml:"deviceList>device"`
|
||||
}
|
||||
|
||||
type Root struct {
|
||||
XMLName xml.Name `xml:"root"`
|
||||
Xmlns string `xml:"xmlns,attr"`
|
||||
SpecVersion SpecVersion `xml:"specVersion"`
|
||||
Device Device `xml:"device"`
|
||||
}
|
||||
|
||||
type ZonePlayer struct {
|
||||
Root *Root
|
||||
HttpClient *http.Client
|
||||
DeviceDescriptionURL *url.URL
|
||||
// services
|
||||
AlarmClock *clk.Service
|
||||
AVTransport *avt.Service
|
||||
ConnectionManager *con.Service
|
||||
ContentDirectory *dir.Service
|
||||
DeviceProperties *dev.Service
|
||||
GroupManagement *gmn.Service
|
||||
GroupRenderingControl *rcg.Service
|
||||
MusicServices *mus.Service
|
||||
QPlay *ply.Service
|
||||
Queue *que.Service
|
||||
RenderingControl *ren.Service
|
||||
SystemProperties *sys.Service
|
||||
VirtualLineIn *vli.Service
|
||||
ZoneGroupTopology *zgt.Service
|
||||
}
|
||||
|
||||
func NewZonePlayer(deviceDescriptionURL *url.URL) (*ZonePlayer, error) {
|
||||
zp := ZonePlayer{
|
||||
Root: &Root{},
|
||||
HttpClient: &http.Client{},
|
||||
DeviceDescriptionURL: deviceDescriptionURL,
|
||||
AlarmClock: clk.NewService(deviceDescriptionURL),
|
||||
AVTransport: avt.NewService(deviceDescriptionURL),
|
||||
ConnectionManager: con.NewService(deviceDescriptionURL),
|
||||
ContentDirectory: dir.NewService(deviceDescriptionURL),
|
||||
DeviceProperties: dev.NewService(deviceDescriptionURL),
|
||||
GroupManagement: gmn.NewService(deviceDescriptionURL),
|
||||
GroupRenderingControl: rcg.NewService(deviceDescriptionURL),
|
||||
MusicServices: mus.NewService(deviceDescriptionURL),
|
||||
QPlay: ply.NewService(deviceDescriptionURL),
|
||||
Queue: que.NewService(deviceDescriptionURL),
|
||||
RenderingControl: ren.NewService(deviceDescriptionURL),
|
||||
SystemProperties: sys.NewService(deviceDescriptionURL),
|
||||
VirtualLineIn: vli.NewService(deviceDescriptionURL),
|
||||
ZoneGroupTopology: zgt.NewService(deviceDescriptionURL),
|
||||
}
|
||||
|
||||
resp, err := zp.HttpClient.Get(zp.DeviceDescriptionURL.String())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
err = xml.Unmarshal(body, zp.Root)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &zp, nil
|
||||
}
|
||||
|
||||
func (z *ZonePlayer) RoomName() string {
|
||||
return z.Root.Device.RoomName
|
||||
}
|
||||
|
||||
func (z *ZonePlayer) ModelName() string {
|
||||
return z.Root.Device.ModelName
|
||||
}
|
||||
|
||||
func (z *ZonePlayer) HardwareVersion() string {
|
||||
return z.Root.Device.HardwareVersion
|
||||
}
|
||||
|
||||
func (z *ZonePlayer) SerialNum() string {
|
||||
return z.Root.Device.SerialNum
|
||||
}
|
||||
|
||||
func (z *ZonePlayer) IsCoordinator() bool {
|
||||
zoneGroupState, err := z.GetZoneGroupState()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
for _, group := range zoneGroupState.ZoneGroups {
|
||||
if "uuid:"+group.Coordinator == z.Root.Device.UDN {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// Convience functions
|
||||
|
||||
func (z *ZonePlayer) GetZoneGroupState() (*ZoneGroupState, error) {
|
||||
zoneGroupStateResponse, err := z.ZoneGroupTopology.GetZoneGroupState(z.HttpClient, &zgt.GetZoneGroupStateArgs{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var zoneGroupState ZoneGroupState
|
||||
err = xml.Unmarshal([]byte(zoneGroupStateResponse.ZoneGroupState), &zoneGroupState)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &zoneGroupState, nil
|
||||
}
|
||||
|
||||
func (z *ZonePlayer) GetVolume() (int, error) {
|
||||
res, err := z.RenderingControl.GetVolume(z.HttpClient, &ren.GetVolumeArgs{Channel: "Master"})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return int(res.CurrentVolume), err
|
||||
}
|
||||
|
||||
func (z *ZonePlayer) SetVolume(desiredVolume int) error {
|
||||
_, err := z.RenderingControl.SetVolume(z.HttpClient, &ren.SetVolumeArgs{
|
||||
Channel: "Master",
|
||||
DesiredVolume: uint16(desiredVolume),
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func (z *ZonePlayer) Play() error {
|
||||
_, err := z.AVTransport.Play(z.HttpClient, &avt.PlayArgs{
|
||||
Speed: "1",
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func (z *ZonePlayer) SetAVTransportURI(url string) error {
|
||||
_, err := z.AVTransport.SetAVTransportURI(z.HttpClient, &avt.SetAVTransportURIArgs{
|
||||
CurrentURI: url,
|
||||
})
|
||||
return err
|
||||
}
|
||||
Vendored
+20
@@ -73,6 +73,9 @@ github.com/goccy/go-json/internal/runtime
|
||||
# github.com/google/uuid v1.3.0
|
||||
## explicit
|
||||
github.com/google/uuid
|
||||
# github.com/holoplot/go-evdev v0.0.0-20230626094006-70c9462cc0f2
|
||||
## explicit; go 1.18
|
||||
github.com/holoplot/go-evdev
|
||||
# github.com/json-iterator/go v1.1.12
|
||||
## explicit; go 1.12
|
||||
github.com/json-iterator/go
|
||||
@@ -205,6 +208,23 @@ github.com/pmezard/go-difflib/difflib
|
||||
## explicit; go 1.20
|
||||
github.com/stretchr/testify/assert
|
||||
github.com/stretchr/testify/require
|
||||
# github.com/szatmary/sonos v0.0.0-20191204204454-000c9219ff0e
|
||||
## explicit
|
||||
github.com/szatmary/sonos
|
||||
github.com/szatmary/sonos/AVTransport
|
||||
github.com/szatmary/sonos/AlarmClock
|
||||
github.com/szatmary/sonos/ConnectionManager
|
||||
github.com/szatmary/sonos/ContentDirectory
|
||||
github.com/szatmary/sonos/DeviceProperties
|
||||
github.com/szatmary/sonos/GroupManagement
|
||||
github.com/szatmary/sonos/GroupRenderingControl
|
||||
github.com/szatmary/sonos/MusicServices
|
||||
github.com/szatmary/sonos/QPlay
|
||||
github.com/szatmary/sonos/Queue
|
||||
github.com/szatmary/sonos/RenderingControl
|
||||
github.com/szatmary/sonos/SystemProperties
|
||||
github.com/szatmary/sonos/VirtualLineIn
|
||||
github.com/szatmary/sonos/ZoneGroupTopology
|
||||
# github.com/tinyzimmer/go-glib v0.0.25
|
||||
## explicit; go 1.16
|
||||
github.com/tinyzimmer/go-glib/glib
|
||||
|
||||
Reference in New Issue
Block a user