diff --git a/.gitignore b/.gitignore index 062567a..003a4d0 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -service* \ No newline at end of file +service* +cert \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json index ed70a24..125342d 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -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" } }, { diff --git a/audio/ding-dong.wav b/audio/ding-dong.wav new file mode 100644 index 0000000..4081daa Binary files /dev/null and b/audio/ding-dong.wav differ diff --git a/go.mod b/go.mod index 3e4cbf6..5f8f151 100644 --- a/go.mod +++ b/go.mod @@ -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 diff --git a/go.sum b/go.sum index 262e068..ea00514 100644 --- a/go.sum +++ b/go.sum @@ -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= diff --git a/main.go b/main.go index d36ee6a..7438d3d 100644 --- a/main.go +++ b/main.go @@ -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 { diff --git a/pkg/common/config.go b/pkg/common/config.go index 438698d..c21a70e 100644 --- a/pkg/common/config.go +++ b/pkg/common/config.go @@ -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"` diff --git a/pkg/ring/ring.go b/pkg/ring/ring.go new file mode 100644 index 0000000..9dcc311 --- /dev/null +++ b/pkg/ring/ring.go @@ -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 +} diff --git a/pkg/ring/sonos/sonos.go b/pkg/ring/sonos/sonos.go new file mode 100644 index 0000000..38e8d40 --- /dev/null +++ b/pkg/ring/sonos/sonos.go @@ -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 + } + } + } +} diff --git a/pkg/server/http.go b/pkg/server/http.go index 7fe6be7..53ed9b7 100644 --- a/pkg/server/http.go +++ b/pkg/server/http.go @@ -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 diff --git a/static/disk.go b/static/disk.go index 1282238..44bfb9f 100644 --- a/static/disk.go +++ b/static/disk.go @@ -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") diff --git a/static/emb.go b/static/emb.go index f7b0cbc..625bf7a 100644 --- a/static/emb.go +++ b/static/emb.go @@ -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") diff --git a/vendor/github.com/holoplot/go-evdev/.gitignore b/vendor/github.com/holoplot/go-evdev/.gitignore new file mode 100644 index 0000000..e52944b --- /dev/null +++ b/vendor/github.com/holoplot/go-evdev/.gitignore @@ -0,0 +1,2 @@ +/evtest +/uinputtest diff --git a/vendor/github.com/holoplot/go-evdev/LICENSE b/vendor/github.com/holoplot/go-evdev/LICENSE new file mode 100644 index 0000000..ef07fcd --- /dev/null +++ b/vendor/github.com/holoplot/go-evdev/LICENSE @@ -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. + diff --git a/vendor/github.com/holoplot/go-evdev/README.md b/vendor/github.com/holoplot/go-evdev/README.md new file mode 100644 index 0000000..bf43e87 --- /dev/null +++ b/vendor/github.com/holoplot/go-evdev/README.md @@ -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. diff --git a/vendor/github.com/holoplot/go-evdev/bitmap.go b/vendor/github.com/holoplot/go-evdev/bitmap.go new file mode 100644 index 0000000..5e3f27e --- /dev/null +++ b/vendor/github.com/holoplot/go-evdev/bitmap.go @@ -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<playback(effect_id = FF_GAIN) is the first effect_id to + // cause a collision with another ff method, in this case ff->set_gain(). + // Therefore the greatest safe value for effect_id is FF_GAIN - 1, + // and thus the total number of effects should never exceed FF_GAIN. + + FF_MAX_EFFECTS = FF_GAIN + + FF_MAX = 0x7f + FF_CNT = (FF_MAX + 1) +) + +// +// Type to String +// + +var INPUTToString = map[EvProp]string{ + INPUT_PROP_POINTER: "INPUT_PROP_POINTER", + INPUT_PROP_DIRECT: "INPUT_PROP_DIRECT", + INPUT_PROP_BUTTONPAD: "INPUT_PROP_BUTTONPAD", + INPUT_PROP_SEMI_MT: "INPUT_PROP_SEMI_MT", + INPUT_PROP_TOPBUTTONPAD: "INPUT_PROP_TOPBUTTONPAD", + INPUT_PROP_POINTING_STICK: "INPUT_PROP_POINTING_STICK", + INPUT_PROP_ACCELEROMETER: "INPUT_PROP_ACCELEROMETER", + + INPUT_PROP_MAX: "INPUT_PROP_MAX", + INPUT_PROP_CNT: "INPUT_PROP_CNT", +} + +var EVToString = map[EvType]string{ + EV_SYN: "EV_SYN", + EV_KEY: "EV_KEY", + EV_REL: "EV_REL", + EV_ABS: "EV_ABS", + EV_MSC: "EV_MSC", + EV_SW: "EV_SW", + EV_LED: "EV_LED", + EV_SND: "EV_SND", + EV_REP: "EV_REP", + EV_FF: "EV_FF", + EV_PWR: "EV_PWR", + EV_FF_STATUS: "EV_FF_STATUS", + EV_MAX: "EV_MAX", + EV_CNT: "EV_CNT", +} + +var SYNToString = map[EvCode]string{ + SYN_REPORT: "SYN_REPORT", + SYN_CONFIG: "SYN_CONFIG", + SYN_MT_REPORT: "SYN_MT_REPORT", + SYN_DROPPED: "SYN_DROPPED", + SYN_MAX: "SYN_MAX", + SYN_CNT: "SYN_CNT", +} + +var KEYToString = map[EvCode]string{ + KEY_RESERVED: "KEY_RESERVED", + KEY_ESC: "KEY_ESC", + KEY_1: "KEY_1", + KEY_2: "KEY_2", + KEY_3: "KEY_3", + KEY_4: "KEY_4", + KEY_5: "KEY_5", + KEY_6: "KEY_6", + KEY_7: "KEY_7", + KEY_8: "KEY_8", + KEY_9: "KEY_9", + KEY_0: "KEY_0", + KEY_MINUS: "KEY_MINUS", + KEY_EQUAL: "KEY_EQUAL", + KEY_BACKSPACE: "KEY_BACKSPACE", + KEY_TAB: "KEY_TAB", + KEY_Q: "KEY_Q", + KEY_W: "KEY_W", + KEY_E: "KEY_E", + KEY_R: "KEY_R", + KEY_T: "KEY_T", + KEY_Y: "KEY_Y", + KEY_U: "KEY_U", + KEY_I: "KEY_I", + KEY_O: "KEY_O", + KEY_P: "KEY_P", + KEY_LEFTBRACE: "KEY_LEFTBRACE", + KEY_RIGHTBRACE: "KEY_RIGHTBRACE", + KEY_ENTER: "KEY_ENTER", + KEY_LEFTCTRL: "KEY_LEFTCTRL", + KEY_A: "KEY_A", + KEY_S: "KEY_S", + KEY_D: "KEY_D", + KEY_F: "KEY_F", + KEY_G: "KEY_G", + KEY_H: "KEY_H", + KEY_J: "KEY_J", + KEY_K: "KEY_K", + KEY_L: "KEY_L", + KEY_SEMICOLON: "KEY_SEMICOLON", + KEY_APOSTROPHE: "KEY_APOSTROPHE", + KEY_GRAVE: "KEY_GRAVE", + KEY_LEFTSHIFT: "KEY_LEFTSHIFT", + KEY_BACKSLASH: "KEY_BACKSLASH", + KEY_Z: "KEY_Z", + KEY_X: "KEY_X", + KEY_C: "KEY_C", + KEY_V: "KEY_V", + KEY_B: "KEY_B", + KEY_N: "KEY_N", + KEY_M: "KEY_M", + KEY_COMMA: "KEY_COMMA", + KEY_DOT: "KEY_DOT", + KEY_SLASH: "KEY_SLASH", + KEY_RIGHTSHIFT: "KEY_RIGHTSHIFT", + KEY_KPASTERISK: "KEY_KPASTERISK", + KEY_LEFTALT: "KEY_LEFTALT", + KEY_SPACE: "KEY_SPACE", + KEY_CAPSLOCK: "KEY_CAPSLOCK", + KEY_F1: "KEY_F1", + KEY_F2: "KEY_F2", + KEY_F3: "KEY_F3", + KEY_F4: "KEY_F4", + KEY_F5: "KEY_F5", + KEY_F6: "KEY_F6", + KEY_F7: "KEY_F7", + KEY_F8: "KEY_F8", + KEY_F9: "KEY_F9", + KEY_F10: "KEY_F10", + KEY_NUMLOCK: "KEY_NUMLOCK", + KEY_SCROLLLOCK: "KEY_SCROLLLOCK", + KEY_KP7: "KEY_KP7", + KEY_KP8: "KEY_KP8", + KEY_KP9: "KEY_KP9", + KEY_KPMINUS: "KEY_KPMINUS", + KEY_KP4: "KEY_KP4", + KEY_KP5: "KEY_KP5", + KEY_KP6: "KEY_KP6", + KEY_KPPLUS: "KEY_KPPLUS", + KEY_KP1: "KEY_KP1", + KEY_KP2: "KEY_KP2", + KEY_KP3: "KEY_KP3", + KEY_KP0: "KEY_KP0", + KEY_KPDOT: "KEY_KPDOT", + + KEY_ZENKAKUHANKAKU: "KEY_ZENKAKUHANKAKU", + KEY_102ND: "KEY_102ND", + KEY_F11: "KEY_F11", + KEY_F12: "KEY_F12", + KEY_RO: "KEY_RO", + KEY_KATAKANA: "KEY_KATAKANA", + KEY_HIRAGANA: "KEY_HIRAGANA", + KEY_HENKAN: "KEY_HENKAN", + KEY_KATAKANAHIRAGANA: "KEY_KATAKANAHIRAGANA", + KEY_MUHENKAN: "KEY_MUHENKAN", + KEY_KPJPCOMMA: "KEY_KPJPCOMMA", + KEY_KPENTER: "KEY_KPENTER", + KEY_RIGHTCTRL: "KEY_RIGHTCTRL", + KEY_KPSLASH: "KEY_KPSLASH", + KEY_SYSRQ: "KEY_SYSRQ", + KEY_RIGHTALT: "KEY_RIGHTALT", + KEY_LINEFEED: "KEY_LINEFEED", + KEY_HOME: "KEY_HOME", + KEY_UP: "KEY_UP", + KEY_PAGEUP: "KEY_PAGEUP", + KEY_LEFT: "KEY_LEFT", + KEY_RIGHT: "KEY_RIGHT", + KEY_END: "KEY_END", + KEY_DOWN: "KEY_DOWN", + KEY_PAGEDOWN: "KEY_PAGEDOWN", + KEY_INSERT: "KEY_INSERT", + KEY_DELETE: "KEY_DELETE", + KEY_MACRO: "KEY_MACRO", + KEY_MUTE: "KEY_MUTE", + KEY_VOLUMEDOWN: "KEY_VOLUMEDOWN", + KEY_VOLUMEUP: "KEY_VOLUMEUP", + KEY_POWER: "KEY_POWER", + KEY_KPEQUAL: "KEY_KPEQUAL", + KEY_KPPLUSMINUS: "KEY_KPPLUSMINUS", + KEY_PAUSE: "KEY_PAUSE", + KEY_SCALE: "KEY_SCALE", + + KEY_KPCOMMA: "KEY_KPCOMMA", + KEY_HANGEUL: "KEY_HANGEUL", + // KEY_HANGUEL: "KEY_HANGUEL", // (KEY_HANGEUL) + KEY_HANJA: "KEY_HANJA", + KEY_YEN: "KEY_YEN", + KEY_LEFTMETA: "KEY_LEFTMETA", + KEY_RIGHTMETA: "KEY_RIGHTMETA", + KEY_COMPOSE: "KEY_COMPOSE", + + KEY_STOP: "KEY_STOP", + KEY_AGAIN: "KEY_AGAIN", + KEY_PROPS: "KEY_PROPS", + KEY_UNDO: "KEY_UNDO", + KEY_FRONT: "KEY_FRONT", + KEY_COPY: "KEY_COPY", + KEY_OPEN: "KEY_OPEN", + KEY_PASTE: "KEY_PASTE", + KEY_FIND: "KEY_FIND", + KEY_CUT: "KEY_CUT", + KEY_HELP: "KEY_HELP", + KEY_MENU: "KEY_MENU", + KEY_CALC: "KEY_CALC", + KEY_SETUP: "KEY_SETUP", + KEY_SLEEP: "KEY_SLEEP", + KEY_WAKEUP: "KEY_WAKEUP", + KEY_FILE: "KEY_FILE", + KEY_SENDFILE: "KEY_SENDFILE", + KEY_DELETEFILE: "KEY_DELETEFILE", + KEY_XFER: "KEY_XFER", + KEY_PROG1: "KEY_PROG1", + KEY_PROG2: "KEY_PROG2", + KEY_WWW: "KEY_WWW", + KEY_MSDOS: "KEY_MSDOS", + KEY_COFFEE: "KEY_COFFEE", + // KEY_SCREENLOCK: "KEY_SCREENLOCK", // (KEY_COFFEE) + KEY_ROTATE_DISPLAY: "KEY_ROTATE_DISPLAY", + // KEY_DIRECTION: "KEY_DIRECTION", // (KEY_ROTATE_DISPLAY) + KEY_CYCLEWINDOWS: "KEY_CYCLEWINDOWS", + KEY_MAIL: "KEY_MAIL", + KEY_BOOKMARKS: "KEY_BOOKMARKS", + KEY_COMPUTER: "KEY_COMPUTER", + KEY_BACK: "KEY_BACK", + KEY_FORWARD: "KEY_FORWARD", + KEY_CLOSECD: "KEY_CLOSECD", + KEY_EJECTCD: "KEY_EJECTCD", + KEY_EJECTCLOSECD: "KEY_EJECTCLOSECD", + KEY_NEXTSONG: "KEY_NEXTSONG", + KEY_PLAYPAUSE: "KEY_PLAYPAUSE", + KEY_PREVIOUSSONG: "KEY_PREVIOUSSONG", + KEY_STOPCD: "KEY_STOPCD", + KEY_RECORD: "KEY_RECORD", + KEY_REWIND: "KEY_REWIND", + KEY_PHONE: "KEY_PHONE", + KEY_ISO: "KEY_ISO", + KEY_CONFIG: "KEY_CONFIG", + KEY_HOMEPAGE: "KEY_HOMEPAGE", + KEY_REFRESH: "KEY_REFRESH", + KEY_EXIT: "KEY_EXIT", + KEY_MOVE: "KEY_MOVE", + KEY_EDIT: "KEY_EDIT", + KEY_SCROLLUP: "KEY_SCROLLUP", + KEY_SCROLLDOWN: "KEY_SCROLLDOWN", + KEY_KPLEFTPAREN: "KEY_KPLEFTPAREN", + KEY_KPRIGHTPAREN: "KEY_KPRIGHTPAREN", + KEY_NEW: "KEY_NEW", + KEY_REDO: "KEY_REDO", + + KEY_F13: "KEY_F13", + KEY_F14: "KEY_F14", + KEY_F15: "KEY_F15", + KEY_F16: "KEY_F16", + KEY_F17: "KEY_F17", + KEY_F18: "KEY_F18", + KEY_F19: "KEY_F19", + KEY_F20: "KEY_F20", + KEY_F21: "KEY_F21", + KEY_F22: "KEY_F22", + KEY_F23: "KEY_F23", + KEY_F24: "KEY_F24", + + KEY_PLAYCD: "KEY_PLAYCD", + KEY_PAUSECD: "KEY_PAUSECD", + KEY_PROG3: "KEY_PROG3", + KEY_PROG4: "KEY_PROG4", + KEY_ALL_APPLICATIONS: "KEY_ALL_APPLICATIONS", + // KEY_DASHBOARD: "KEY_DASHBOARD", // (KEY_ALL_APPLICATIONS) + KEY_SUSPEND: "KEY_SUSPEND", + KEY_CLOSE: "KEY_CLOSE", + KEY_PLAY: "KEY_PLAY", + KEY_FASTFORWARD: "KEY_FASTFORWARD", + KEY_BASSBOOST: "KEY_BASSBOOST", + KEY_PRINT: "KEY_PRINT", + KEY_HP: "KEY_HP", + KEY_CAMERA: "KEY_CAMERA", + KEY_SOUND: "KEY_SOUND", + KEY_QUESTION: "KEY_QUESTION", + KEY_EMAIL: "KEY_EMAIL", + KEY_CHAT: "KEY_CHAT", + KEY_SEARCH: "KEY_SEARCH", + KEY_CONNECT: "KEY_CONNECT", + KEY_FINANCE: "KEY_FINANCE", + KEY_SPORT: "KEY_SPORT", + KEY_SHOP: "KEY_SHOP", + KEY_ALTERASE: "KEY_ALTERASE", + KEY_CANCEL: "KEY_CANCEL", + KEY_BRIGHTNESSDOWN: "KEY_BRIGHTNESSDOWN", + KEY_BRIGHTNESSUP: "KEY_BRIGHTNESSUP", + KEY_MEDIA: "KEY_MEDIA", + + KEY_SWITCHVIDEOMODE: "KEY_SWITCHVIDEOMODE", + KEY_KBDILLUMTOGGLE: "KEY_KBDILLUMTOGGLE", + KEY_KBDILLUMDOWN: "KEY_KBDILLUMDOWN", + KEY_KBDILLUMUP: "KEY_KBDILLUMUP", + + KEY_SEND: "KEY_SEND", + KEY_REPLY: "KEY_REPLY", + KEY_FORWARDMAIL: "KEY_FORWARDMAIL", + KEY_SAVE: "KEY_SAVE", + KEY_DOCUMENTS: "KEY_DOCUMENTS", + + KEY_BATTERY: "KEY_BATTERY", + + KEY_BLUETOOTH: "KEY_BLUETOOTH", + KEY_WLAN: "KEY_WLAN", + KEY_UWB: "KEY_UWB", + + KEY_UNKNOWN: "KEY_UNKNOWN", + + KEY_VIDEO_NEXT: "KEY_VIDEO_NEXT", + KEY_VIDEO_PREV: "KEY_VIDEO_PREV", + KEY_BRIGHTNESS_CYCLE: "KEY_BRIGHTNESS_CYCLE", + KEY_BRIGHTNESS_AUTO: "KEY_BRIGHTNESS_AUTO", + // KEY_BRIGHTNESS_ZERO: "KEY_BRIGHTNESS_ZERO", // (KEY_BRIGHTNESS_AUTO) + KEY_DISPLAY_OFF: "KEY_DISPLAY_OFF", + + KEY_WWAN: "KEY_WWAN", + // KEY_WIMAX: "KEY_WIMAX", // (KEY_WWAN) + KEY_RFKILL: "KEY_RFKILL", + + KEY_MICMUTE: "KEY_MICMUTE", + + BTN_MISC: "BTN_MISC", + // BTN_0: "BTN_0", // (BTN_MISC) + BTN_1: "BTN_1", + BTN_2: "BTN_2", + BTN_3: "BTN_3", + BTN_4: "BTN_4", + BTN_5: "BTN_5", + BTN_6: "BTN_6", + BTN_7: "BTN_7", + BTN_8: "BTN_8", + BTN_9: "BTN_9", + + BTN_MOUSE: "BTN_MOUSE", + // BTN_LEFT: "BTN_LEFT", // (BTN_MOUSE) + BTN_RIGHT: "BTN_RIGHT", + BTN_MIDDLE: "BTN_MIDDLE", + BTN_SIDE: "BTN_SIDE", + BTN_EXTRA: "BTN_EXTRA", + BTN_FORWARD: "BTN_FORWARD", + BTN_BACK: "BTN_BACK", + BTN_TASK: "BTN_TASK", + + BTN_JOYSTICK: "BTN_JOYSTICK", + // BTN_TRIGGER: "BTN_TRIGGER", // (BTN_JOYSTICK) + BTN_THUMB: "BTN_THUMB", + BTN_THUMB2: "BTN_THUMB2", + BTN_TOP: "BTN_TOP", + BTN_TOP2: "BTN_TOP2", + BTN_PINKIE: "BTN_PINKIE", + BTN_BASE: "BTN_BASE", + BTN_BASE2: "BTN_BASE2", + BTN_BASE3: "BTN_BASE3", + BTN_BASE4: "BTN_BASE4", + BTN_BASE5: "BTN_BASE5", + BTN_BASE6: "BTN_BASE6", + BTN_DEAD: "BTN_DEAD", + + BTN_GAMEPAD: "BTN_GAMEPAD", + // BTN_SOUTH: "BTN_SOUTH", // (BTN_GAMEPAD) + // BTN_A: "BTN_A", // (BTN_GAMEPAD) + BTN_EAST: "BTN_EAST", + // BTN_B: "BTN_B", // (BTN_EAST) + BTN_C: "BTN_C", + BTN_NORTH: "BTN_NORTH", + // BTN_X: "BTN_X", // (BTN_NORTH) + BTN_WEST: "BTN_WEST", + // BTN_Y: "BTN_Y", // (BTN_WEST) + BTN_Z: "BTN_Z", + BTN_TL: "BTN_TL", + BTN_TR: "BTN_TR", + BTN_TL2: "BTN_TL2", + BTN_TR2: "BTN_TR2", + BTN_SELECT: "BTN_SELECT", + BTN_START: "BTN_START", + BTN_MODE: "BTN_MODE", + BTN_THUMBL: "BTN_THUMBL", + BTN_THUMBR: "BTN_THUMBR", + + BTN_DIGI: "BTN_DIGI", + // BTN_TOOL_PEN: "BTN_TOOL_PEN", // (BTN_DIGI) + BTN_TOOL_RUBBER: "BTN_TOOL_RUBBER", + BTN_TOOL_BRUSH: "BTN_TOOL_BRUSH", + BTN_TOOL_PENCIL: "BTN_TOOL_PENCIL", + BTN_TOOL_AIRBRUSH: "BTN_TOOL_AIRBRUSH", + BTN_TOOL_FINGER: "BTN_TOOL_FINGER", + BTN_TOOL_MOUSE: "BTN_TOOL_MOUSE", + BTN_TOOL_LENS: "BTN_TOOL_LENS", + BTN_TOOL_QUINTTAP: "BTN_TOOL_QUINTTAP", + BTN_STYLUS3: "BTN_STYLUS3", + BTN_TOUCH: "BTN_TOUCH", + BTN_STYLUS: "BTN_STYLUS", + BTN_STYLUS2: "BTN_STYLUS2", + BTN_TOOL_DOUBLETAP: "BTN_TOOL_DOUBLETAP", + BTN_TOOL_TRIPLETAP: "BTN_TOOL_TRIPLETAP", + BTN_TOOL_QUADTAP: "BTN_TOOL_QUADTAP", + + BTN_WHEEL: "BTN_WHEEL", + // BTN_GEAR_DOWN: "BTN_GEAR_DOWN", // (BTN_WHEEL) + BTN_GEAR_UP: "BTN_GEAR_UP", + + KEY_OK: "KEY_OK", + KEY_SELECT: "KEY_SELECT", + KEY_GOTO: "KEY_GOTO", + KEY_CLEAR: "KEY_CLEAR", + KEY_POWER2: "KEY_POWER2", + KEY_OPTION: "KEY_OPTION", + KEY_INFO: "KEY_INFO", + KEY_TIME: "KEY_TIME", + KEY_VENDOR: "KEY_VENDOR", + KEY_ARCHIVE: "KEY_ARCHIVE", + KEY_PROGRAM: "KEY_PROGRAM", + KEY_CHANNEL: "KEY_CHANNEL", + KEY_FAVORITES: "KEY_FAVORITES", + KEY_EPG: "KEY_EPG", + KEY_PVR: "KEY_PVR", + KEY_MHP: "KEY_MHP", + KEY_LANGUAGE: "KEY_LANGUAGE", + KEY_TITLE: "KEY_TITLE", + KEY_SUBTITLE: "KEY_SUBTITLE", + KEY_ANGLE: "KEY_ANGLE", + KEY_FULL_SCREEN: "KEY_FULL_SCREEN", + // KEY_ZOOM: "KEY_ZOOM", // (KEY_FULL_SCREEN) + KEY_MODE: "KEY_MODE", + KEY_KEYBOARD: "KEY_KEYBOARD", + KEY_ASPECT_RATIO: "KEY_ASPECT_RATIO", + // KEY_SCREEN: "KEY_SCREEN", // (KEY_ASPECT_RATIO) + KEY_PC: "KEY_PC", + KEY_TV: "KEY_TV", + KEY_TV2: "KEY_TV2", + KEY_VCR: "KEY_VCR", + KEY_VCR2: "KEY_VCR2", + KEY_SAT: "KEY_SAT", + KEY_SAT2: "KEY_SAT2", + KEY_CD: "KEY_CD", + KEY_TAPE: "KEY_TAPE", + KEY_RADIO: "KEY_RADIO", + KEY_TUNER: "KEY_TUNER", + KEY_PLAYER: "KEY_PLAYER", + KEY_TEXT: "KEY_TEXT", + KEY_DVD: "KEY_DVD", + KEY_AUX: "KEY_AUX", + KEY_MP3: "KEY_MP3", + KEY_AUDIO: "KEY_AUDIO", + KEY_VIDEO: "KEY_VIDEO", + KEY_DIRECTORY: "KEY_DIRECTORY", + KEY_LIST: "KEY_LIST", + KEY_MEMO: "KEY_MEMO", + KEY_CALENDAR: "KEY_CALENDAR", + KEY_RED: "KEY_RED", + KEY_GREEN: "KEY_GREEN", + KEY_YELLOW: "KEY_YELLOW", + KEY_BLUE: "KEY_BLUE", + KEY_CHANNELUP: "KEY_CHANNELUP", + KEY_CHANNELDOWN: "KEY_CHANNELDOWN", + KEY_FIRST: "KEY_FIRST", + KEY_LAST: "KEY_LAST", + KEY_AB: "KEY_AB", + KEY_NEXT: "KEY_NEXT", + KEY_RESTART: "KEY_RESTART", + KEY_SLOW: "KEY_SLOW", + KEY_SHUFFLE: "KEY_SHUFFLE", + KEY_BREAK: "KEY_BREAK", + KEY_PREVIOUS: "KEY_PREVIOUS", + KEY_DIGITS: "KEY_DIGITS", + KEY_TEEN: "KEY_TEEN", + KEY_TWEN: "KEY_TWEN", + KEY_VIDEOPHONE: "KEY_VIDEOPHONE", + KEY_GAMES: "KEY_GAMES", + KEY_ZOOMIN: "KEY_ZOOMIN", + KEY_ZOOMOUT: "KEY_ZOOMOUT", + KEY_ZOOMRESET: "KEY_ZOOMRESET", + KEY_WORDPROCESSOR: "KEY_WORDPROCESSOR", + KEY_EDITOR: "KEY_EDITOR", + KEY_SPREADSHEET: "KEY_SPREADSHEET", + KEY_GRAPHICSEDITOR: "KEY_GRAPHICSEDITOR", + KEY_PRESENTATION: "KEY_PRESENTATION", + KEY_DATABASE: "KEY_DATABASE", + KEY_NEWS: "KEY_NEWS", + KEY_VOICEMAIL: "KEY_VOICEMAIL", + KEY_ADDRESSBOOK: "KEY_ADDRESSBOOK", + KEY_MESSENGER: "KEY_MESSENGER", + KEY_DISPLAYTOGGLE: "KEY_DISPLAYTOGGLE", + // KEY_BRIGHTNESS_TOGGLE: "KEY_BRIGHTNESS_TOGGLE", // (KEY_DISPLAYTOGGLE) + KEY_SPELLCHECK: "KEY_SPELLCHECK", + KEY_LOGOFF: "KEY_LOGOFF", + + KEY_DOLLAR: "KEY_DOLLAR", + KEY_EURO: "KEY_EURO", + + KEY_FRAMEBACK: "KEY_FRAMEBACK", + KEY_FRAMEFORWARD: "KEY_FRAMEFORWARD", + KEY_CONTEXT_MENU: "KEY_CONTEXT_MENU", + KEY_MEDIA_REPEAT: "KEY_MEDIA_REPEAT", + KEY_10CHANNELSUP: "KEY_10CHANNELSUP", + KEY_10CHANNELSDOWN: "KEY_10CHANNELSDOWN", + KEY_IMAGES: "KEY_IMAGES", + KEY_NOTIFICATION_CENTER: "KEY_NOTIFICATION_CENTER", + KEY_PICKUP_PHONE: "KEY_PICKUP_PHONE", + KEY_HANGUP_PHONE: "KEY_HANGUP_PHONE", + + KEY_DEL_EOL: "KEY_DEL_EOL", + KEY_DEL_EOS: "KEY_DEL_EOS", + KEY_INS_LINE: "KEY_INS_LINE", + KEY_DEL_LINE: "KEY_DEL_LINE", + + KEY_FN: "KEY_FN", + KEY_FN_ESC: "KEY_FN_ESC", + KEY_FN_F1: "KEY_FN_F1", + KEY_FN_F2: "KEY_FN_F2", + KEY_FN_F3: "KEY_FN_F3", + KEY_FN_F4: "KEY_FN_F4", + KEY_FN_F5: "KEY_FN_F5", + KEY_FN_F6: "KEY_FN_F6", + KEY_FN_F7: "KEY_FN_F7", + KEY_FN_F8: "KEY_FN_F8", + KEY_FN_F9: "KEY_FN_F9", + KEY_FN_F10: "KEY_FN_F10", + KEY_FN_F11: "KEY_FN_F11", + KEY_FN_F12: "KEY_FN_F12", + KEY_FN_1: "KEY_FN_1", + KEY_FN_2: "KEY_FN_2", + KEY_FN_D: "KEY_FN_D", + KEY_FN_E: "KEY_FN_E", + KEY_FN_F: "KEY_FN_F", + KEY_FN_S: "KEY_FN_S", + KEY_FN_B: "KEY_FN_B", + KEY_FN_RIGHT_SHIFT: "KEY_FN_RIGHT_SHIFT", + + KEY_BRL_DOT1: "KEY_BRL_DOT1", + KEY_BRL_DOT2: "KEY_BRL_DOT2", + KEY_BRL_DOT3: "KEY_BRL_DOT3", + KEY_BRL_DOT4: "KEY_BRL_DOT4", + KEY_BRL_DOT5: "KEY_BRL_DOT5", + KEY_BRL_DOT6: "KEY_BRL_DOT6", + KEY_BRL_DOT7: "KEY_BRL_DOT7", + KEY_BRL_DOT8: "KEY_BRL_DOT8", + KEY_BRL_DOT9: "KEY_BRL_DOT9", + KEY_BRL_DOT10: "KEY_BRL_DOT10", + + KEY_NUMERIC_0: "KEY_NUMERIC_0", + KEY_NUMERIC_1: "KEY_NUMERIC_1", + KEY_NUMERIC_2: "KEY_NUMERIC_2", + KEY_NUMERIC_3: "KEY_NUMERIC_3", + KEY_NUMERIC_4: "KEY_NUMERIC_4", + KEY_NUMERIC_5: "KEY_NUMERIC_5", + KEY_NUMERIC_6: "KEY_NUMERIC_6", + KEY_NUMERIC_7: "KEY_NUMERIC_7", + KEY_NUMERIC_8: "KEY_NUMERIC_8", + KEY_NUMERIC_9: "KEY_NUMERIC_9", + KEY_NUMERIC_STAR: "KEY_NUMERIC_STAR", + KEY_NUMERIC_POUND: "KEY_NUMERIC_POUND", + KEY_NUMERIC_A: "KEY_NUMERIC_A", + KEY_NUMERIC_B: "KEY_NUMERIC_B", + KEY_NUMERIC_C: "KEY_NUMERIC_C", + KEY_NUMERIC_D: "KEY_NUMERIC_D", + + KEY_CAMERA_FOCUS: "KEY_CAMERA_FOCUS", + KEY_WPS_BUTTON: "KEY_WPS_BUTTON", + + KEY_TOUCHPAD_TOGGLE: "KEY_TOUCHPAD_TOGGLE", + KEY_TOUCHPAD_ON: "KEY_TOUCHPAD_ON", + KEY_TOUCHPAD_OFF: "KEY_TOUCHPAD_OFF", + + KEY_CAMERA_ZOOMIN: "KEY_CAMERA_ZOOMIN", + KEY_CAMERA_ZOOMOUT: "KEY_CAMERA_ZOOMOUT", + KEY_CAMERA_UP: "KEY_CAMERA_UP", + KEY_CAMERA_DOWN: "KEY_CAMERA_DOWN", + KEY_CAMERA_LEFT: "KEY_CAMERA_LEFT", + KEY_CAMERA_RIGHT: "KEY_CAMERA_RIGHT", + + KEY_ATTENDANT_ON: "KEY_ATTENDANT_ON", + KEY_ATTENDANT_OFF: "KEY_ATTENDANT_OFF", + KEY_ATTENDANT_TOGGLE: "KEY_ATTENDANT_TOGGLE", + KEY_LIGHTS_TOGGLE: "KEY_LIGHTS_TOGGLE", + + BTN_DPAD_UP: "BTN_DPAD_UP", + BTN_DPAD_DOWN: "BTN_DPAD_DOWN", + BTN_DPAD_LEFT: "BTN_DPAD_LEFT", + BTN_DPAD_RIGHT: "BTN_DPAD_RIGHT", + + KEY_ALS_TOGGLE: "KEY_ALS_TOGGLE", + KEY_ROTATE_LOCK_TOGGLE: "KEY_ROTATE_LOCK_TOGGLE", + + KEY_BUTTONCONFIG: "KEY_BUTTONCONFIG", + KEY_TASKMANAGER: "KEY_TASKMANAGER", + KEY_JOURNAL: "KEY_JOURNAL", + KEY_CONTROLPANEL: "KEY_CONTROLPANEL", + KEY_APPSELECT: "KEY_APPSELECT", + KEY_SCREENSAVER: "KEY_SCREENSAVER", + KEY_VOICECOMMAND: "KEY_VOICECOMMAND", + KEY_ASSISTANT: "KEY_ASSISTANT", + KEY_KBD_LAYOUT_NEXT: "KEY_KBD_LAYOUT_NEXT", + KEY_EMOJI_PICKER: "KEY_EMOJI_PICKER", + KEY_DICTATE: "KEY_DICTATE", + + KEY_BRIGHTNESS_MIN: "KEY_BRIGHTNESS_MIN", + KEY_BRIGHTNESS_MAX: "KEY_BRIGHTNESS_MAX", + + KEY_KBDINPUTASSIST_PREV: "KEY_KBDINPUTASSIST_PREV", + KEY_KBDINPUTASSIST_NEXT: "KEY_KBDINPUTASSIST_NEXT", + KEY_KBDINPUTASSIST_PREVGROUP: "KEY_KBDINPUTASSIST_PREVGROUP", + KEY_KBDINPUTASSIST_NEXTGROUP: "KEY_KBDINPUTASSIST_NEXTGROUP", + KEY_KBDINPUTASSIST_ACCEPT: "KEY_KBDINPUTASSIST_ACCEPT", + KEY_KBDINPUTASSIST_CANCEL: "KEY_KBDINPUTASSIST_CANCEL", + + KEY_RIGHT_UP: "KEY_RIGHT_UP", + KEY_RIGHT_DOWN: "KEY_RIGHT_DOWN", + KEY_LEFT_UP: "KEY_LEFT_UP", + KEY_LEFT_DOWN: "KEY_LEFT_DOWN", + + KEY_ROOT_MENU: "KEY_ROOT_MENU", + + KEY_MEDIA_TOP_MENU: "KEY_MEDIA_TOP_MENU", + KEY_NUMERIC_11: "KEY_NUMERIC_11", + KEY_NUMERIC_12: "KEY_NUMERIC_12", + + KEY_AUDIO_DESC: "KEY_AUDIO_DESC", + KEY_3D_MODE: "KEY_3D_MODE", + KEY_NEXT_FAVORITE: "KEY_NEXT_FAVORITE", + KEY_STOP_RECORD: "KEY_STOP_RECORD", + KEY_PAUSE_RECORD: "KEY_PAUSE_RECORD", + KEY_VOD: "KEY_VOD", + KEY_UNMUTE: "KEY_UNMUTE", + KEY_FASTREVERSE: "KEY_FASTREVERSE", + KEY_SLOWREVERSE: "KEY_SLOWREVERSE", + + KEY_DATA: "KEY_DATA", + KEY_ONSCREEN_KEYBOARD: "KEY_ONSCREEN_KEYBOARD", + + KEY_PRIVACY_SCREEN_TOGGLE: "KEY_PRIVACY_SCREEN_TOGGLE", + + KEY_SELECTIVE_SCREENSHOT: "KEY_SELECTIVE_SCREENSHOT", + + KEY_MACRO1: "KEY_MACRO1", + KEY_MACRO2: "KEY_MACRO2", + KEY_MACRO3: "KEY_MACRO3", + KEY_MACRO4: "KEY_MACRO4", + KEY_MACRO5: "KEY_MACRO5", + KEY_MACRO6: "KEY_MACRO6", + KEY_MACRO7: "KEY_MACRO7", + KEY_MACRO8: "KEY_MACRO8", + KEY_MACRO9: "KEY_MACRO9", + KEY_MACRO10: "KEY_MACRO10", + KEY_MACRO11: "KEY_MACRO11", + KEY_MACRO12: "KEY_MACRO12", + KEY_MACRO13: "KEY_MACRO13", + KEY_MACRO14: "KEY_MACRO14", + KEY_MACRO15: "KEY_MACRO15", + KEY_MACRO16: "KEY_MACRO16", + KEY_MACRO17: "KEY_MACRO17", + KEY_MACRO18: "KEY_MACRO18", + KEY_MACRO19: "KEY_MACRO19", + KEY_MACRO20: "KEY_MACRO20", + KEY_MACRO21: "KEY_MACRO21", + KEY_MACRO22: "KEY_MACRO22", + KEY_MACRO23: "KEY_MACRO23", + KEY_MACRO24: "KEY_MACRO24", + KEY_MACRO25: "KEY_MACRO25", + KEY_MACRO26: "KEY_MACRO26", + KEY_MACRO27: "KEY_MACRO27", + KEY_MACRO28: "KEY_MACRO28", + KEY_MACRO29: "KEY_MACRO29", + KEY_MACRO30: "KEY_MACRO30", + + KEY_MACRO_RECORD_START: "KEY_MACRO_RECORD_START", + KEY_MACRO_RECORD_STOP: "KEY_MACRO_RECORD_STOP", + KEY_MACRO_PRESET_CYCLE: "KEY_MACRO_PRESET_CYCLE", + KEY_MACRO_PRESET1: "KEY_MACRO_PRESET1", + KEY_MACRO_PRESET2: "KEY_MACRO_PRESET2", + KEY_MACRO_PRESET3: "KEY_MACRO_PRESET3", + + KEY_KBD_LCD_MENU1: "KEY_KBD_LCD_MENU1", + KEY_KBD_LCD_MENU2: "KEY_KBD_LCD_MENU2", + KEY_KBD_LCD_MENU3: "KEY_KBD_LCD_MENU3", + KEY_KBD_LCD_MENU4: "KEY_KBD_LCD_MENU4", + KEY_KBD_LCD_MENU5: "KEY_KBD_LCD_MENU5", + + BTN_TRIGGER_HAPPY: "BTN_TRIGGER_HAPPY", + // BTN_TRIGGER_HAPPY1: "BTN_TRIGGER_HAPPY1", // (BTN_TRIGGER_HAPPY) + BTN_TRIGGER_HAPPY2: "BTN_TRIGGER_HAPPY2", + BTN_TRIGGER_HAPPY3: "BTN_TRIGGER_HAPPY3", + BTN_TRIGGER_HAPPY4: "BTN_TRIGGER_HAPPY4", + BTN_TRIGGER_HAPPY5: "BTN_TRIGGER_HAPPY5", + BTN_TRIGGER_HAPPY6: "BTN_TRIGGER_HAPPY6", + BTN_TRIGGER_HAPPY7: "BTN_TRIGGER_HAPPY7", + BTN_TRIGGER_HAPPY8: "BTN_TRIGGER_HAPPY8", + BTN_TRIGGER_HAPPY9: "BTN_TRIGGER_HAPPY9", + BTN_TRIGGER_HAPPY10: "BTN_TRIGGER_HAPPY10", + BTN_TRIGGER_HAPPY11: "BTN_TRIGGER_HAPPY11", + BTN_TRIGGER_HAPPY12: "BTN_TRIGGER_HAPPY12", + BTN_TRIGGER_HAPPY13: "BTN_TRIGGER_HAPPY13", + BTN_TRIGGER_HAPPY14: "BTN_TRIGGER_HAPPY14", + BTN_TRIGGER_HAPPY15: "BTN_TRIGGER_HAPPY15", + BTN_TRIGGER_HAPPY16: "BTN_TRIGGER_HAPPY16", + BTN_TRIGGER_HAPPY17: "BTN_TRIGGER_HAPPY17", + BTN_TRIGGER_HAPPY18: "BTN_TRIGGER_HAPPY18", + BTN_TRIGGER_HAPPY19: "BTN_TRIGGER_HAPPY19", + BTN_TRIGGER_HAPPY20: "BTN_TRIGGER_HAPPY20", + BTN_TRIGGER_HAPPY21: "BTN_TRIGGER_HAPPY21", + BTN_TRIGGER_HAPPY22: "BTN_TRIGGER_HAPPY22", + BTN_TRIGGER_HAPPY23: "BTN_TRIGGER_HAPPY23", + BTN_TRIGGER_HAPPY24: "BTN_TRIGGER_HAPPY24", + BTN_TRIGGER_HAPPY25: "BTN_TRIGGER_HAPPY25", + BTN_TRIGGER_HAPPY26: "BTN_TRIGGER_HAPPY26", + BTN_TRIGGER_HAPPY27: "BTN_TRIGGER_HAPPY27", + BTN_TRIGGER_HAPPY28: "BTN_TRIGGER_HAPPY28", + BTN_TRIGGER_HAPPY29: "BTN_TRIGGER_HAPPY29", + BTN_TRIGGER_HAPPY30: "BTN_TRIGGER_HAPPY30", + BTN_TRIGGER_HAPPY31: "BTN_TRIGGER_HAPPY31", + BTN_TRIGGER_HAPPY32: "BTN_TRIGGER_HAPPY32", + BTN_TRIGGER_HAPPY33: "BTN_TRIGGER_HAPPY33", + BTN_TRIGGER_HAPPY34: "BTN_TRIGGER_HAPPY34", + BTN_TRIGGER_HAPPY35: "BTN_TRIGGER_HAPPY35", + BTN_TRIGGER_HAPPY36: "BTN_TRIGGER_HAPPY36", + BTN_TRIGGER_HAPPY37: "BTN_TRIGGER_HAPPY37", + BTN_TRIGGER_HAPPY38: "BTN_TRIGGER_HAPPY38", + BTN_TRIGGER_HAPPY39: "BTN_TRIGGER_HAPPY39", + BTN_TRIGGER_HAPPY40: "BTN_TRIGGER_HAPPY40", + + // KEY_MIN_INTERESTING: "KEY_MIN_INTERESTING", // (KEY_MUTE) + KEY_MAX: "KEY_MAX", + KEY_CNT: "KEY_CNT", +} + +var RELToString = map[EvCode]string{ + REL_X: "REL_X", + REL_Y: "REL_Y", + REL_Z: "REL_Z", + REL_RX: "REL_RX", + REL_RY: "REL_RY", + REL_RZ: "REL_RZ", + REL_HWHEEL: "REL_HWHEEL", + REL_DIAL: "REL_DIAL", + REL_WHEEL: "REL_WHEEL", + REL_MISC: "REL_MISC", + + REL_RESERVED: "REL_RESERVED", + REL_WHEEL_HI_RES: "REL_WHEEL_HI_RES", + REL_HWHEEL_HI_RES: "REL_HWHEEL_HI_RES", + REL_MAX: "REL_MAX", + REL_CNT: "REL_CNT", +} + +var ABSToString = map[EvCode]string{ + ABS_X: "ABS_X", + ABS_Y: "ABS_Y", + ABS_Z: "ABS_Z", + ABS_RX: "ABS_RX", + ABS_RY: "ABS_RY", + ABS_RZ: "ABS_RZ", + ABS_THROTTLE: "ABS_THROTTLE", + ABS_RUDDER: "ABS_RUDDER", + ABS_WHEEL: "ABS_WHEEL", + ABS_GAS: "ABS_GAS", + ABS_BRAKE: "ABS_BRAKE", + ABS_HAT0X: "ABS_HAT0X", + ABS_HAT0Y: "ABS_HAT0Y", + ABS_HAT1X: "ABS_HAT1X", + ABS_HAT1Y: "ABS_HAT1Y", + ABS_HAT2X: "ABS_HAT2X", + ABS_HAT2Y: "ABS_HAT2Y", + ABS_HAT3X: "ABS_HAT3X", + ABS_HAT3Y: "ABS_HAT3Y", + ABS_PRESSURE: "ABS_PRESSURE", + ABS_DISTANCE: "ABS_DISTANCE", + ABS_TILT_X: "ABS_TILT_X", + ABS_TILT_Y: "ABS_TILT_Y", + ABS_TOOL_WIDTH: "ABS_TOOL_WIDTH", + + ABS_VOLUME: "ABS_VOLUME", + + ABS_MISC: "ABS_MISC", + + ABS_RESERVED: "ABS_RESERVED", + + ABS_MT_SLOT: "ABS_MT_SLOT", + ABS_MT_TOUCH_MAJOR: "ABS_MT_TOUCH_MAJOR", + ABS_MT_TOUCH_MINOR: "ABS_MT_TOUCH_MINOR", + ABS_MT_WIDTH_MAJOR: "ABS_MT_WIDTH_MAJOR", + ABS_MT_WIDTH_MINOR: "ABS_MT_WIDTH_MINOR", + ABS_MT_ORIENTATION: "ABS_MT_ORIENTATION", + ABS_MT_POSITION_X: "ABS_MT_POSITION_X", + ABS_MT_POSITION_Y: "ABS_MT_POSITION_Y", + ABS_MT_TOOL_TYPE: "ABS_MT_TOOL_TYPE", + ABS_MT_BLOB_ID: "ABS_MT_BLOB_ID", + ABS_MT_TRACKING_ID: "ABS_MT_TRACKING_ID", + ABS_MT_PRESSURE: "ABS_MT_PRESSURE", + ABS_MT_DISTANCE: "ABS_MT_DISTANCE", + ABS_MT_TOOL_X: "ABS_MT_TOOL_X", + ABS_MT_TOOL_Y: "ABS_MT_TOOL_Y", + + ABS_MAX: "ABS_MAX", + ABS_CNT: "ABS_CNT", +} + +var SWToString = map[EvCode]string{ + SW_LID: "SW_LID", + SW_TABLET_MODE: "SW_TABLET_MODE", + SW_HEADPHONE_INSERT: "SW_HEADPHONE_INSERT", + SW_RFKILL_ALL: "SW_RFKILL_ALL", + // SW_RADIO: "SW_RADIO", // (SW_RFKILL_ALL) + SW_MICROPHONE_INSERT: "SW_MICROPHONE_INSERT", + SW_DOCK: "SW_DOCK", + SW_LINEOUT_INSERT: "SW_LINEOUT_INSERT", + SW_JACK_PHYSICAL_INSERT: "SW_JACK_PHYSICAL_INSERT", + SW_VIDEOOUT_INSERT: "SW_VIDEOOUT_INSERT", + SW_CAMERA_LENS_COVER: "SW_CAMERA_LENS_COVER", + SW_KEYPAD_SLIDE: "SW_KEYPAD_SLIDE", + SW_FRONT_PROXIMITY: "SW_FRONT_PROXIMITY", + SW_ROTATE_LOCK: "SW_ROTATE_LOCK", + SW_LINEIN_INSERT: "SW_LINEIN_INSERT", + SW_MUTE_DEVICE: "SW_MUTE_DEVICE", + SW_PEN_INSERTED: "SW_PEN_INSERTED", + SW_MACHINE_COVER: "SW_MACHINE_COVER", + // SW_MAX: "SW_MAX", // (SW_MACHINE_COVER) + SW_CNT: "SW_CNT", +} + +var MSCToString = map[EvCode]string{ + MSC_SERIAL: "MSC_SERIAL", + MSC_PULSELED: "MSC_PULSELED", + MSC_GESTURE: "MSC_GESTURE", + MSC_RAW: "MSC_RAW", + MSC_SCAN: "MSC_SCAN", + MSC_TIMESTAMP: "MSC_TIMESTAMP", + MSC_MAX: "MSC_MAX", + MSC_CNT: "MSC_CNT", +} + +var LEDToString = map[EvCode]string{ + LED_NUML: "LED_NUML", + LED_CAPSL: "LED_CAPSL", + LED_SCROLLL: "LED_SCROLLL", + LED_COMPOSE: "LED_COMPOSE", + LED_KANA: "LED_KANA", + LED_SLEEP: "LED_SLEEP", + LED_SUSPEND: "LED_SUSPEND", + LED_MUTE: "LED_MUTE", + LED_MISC: "LED_MISC", + LED_MAIL: "LED_MAIL", + LED_CHARGING: "LED_CHARGING", + LED_MAX: "LED_MAX", + LED_CNT: "LED_CNT", +} + +var REPToString = map[EvCode]string{ + REP_DELAY: "REP_DELAY", + REP_PERIOD: "REP_PERIOD", + // REP_MAX: "REP_MAX", // (REP_PERIOD) + REP_CNT: "REP_CNT", +} + +var SNDToString = map[EvCode]string{ + SND_CLICK: "SND_CLICK", + SND_BELL: "SND_BELL", + SND_TONE: "SND_TONE", + SND_MAX: "SND_MAX", + SND_CNT: "SND_CNT", +} + +var IDToString = map[EvCode]string{ + ID_BUS: "ID_BUS", + ID_VENDOR: "ID_VENDOR", + ID_PRODUCT: "ID_PRODUCT", + ID_VERSION: "ID_VERSION", +} + +var BUSToString = map[EvCode]string{ + BUS_PCI: "BUS_PCI", + BUS_ISAPNP: "BUS_ISAPNP", + BUS_USB: "BUS_USB", + BUS_HIL: "BUS_HIL", + BUS_BLUETOOTH: "BUS_BLUETOOTH", + BUS_VIRTUAL: "BUS_VIRTUAL", + + BUS_ISA: "BUS_ISA", + BUS_I8042: "BUS_I8042", + BUS_XTKBD: "BUS_XTKBD", + BUS_RS232: "BUS_RS232", + BUS_GAMEPORT: "BUS_GAMEPORT", + BUS_PARPORT: "BUS_PARPORT", + BUS_AMIGA: "BUS_AMIGA", + BUS_ADB: "BUS_ADB", + BUS_I2C: "BUS_I2C", + BUS_HOST: "BUS_HOST", + BUS_GSC: "BUS_GSC", + BUS_ATARI: "BUS_ATARI", + BUS_SPI: "BUS_SPI", + BUS_RMI: "BUS_RMI", + BUS_CEC: "BUS_CEC", + BUS_INTEL_ISHTP: "BUS_INTEL_ISHTP", +} + +var MTToString = map[EvCode]string{ + MT_TOOL_FINGER: "MT_TOOL_FINGER", + MT_TOOL_PEN: "MT_TOOL_PEN", + MT_TOOL_PALM: "MT_TOOL_PALM", + MT_TOOL_DIAL: "MT_TOOL_DIAL", + MT_TOOL_MAX: "MT_TOOL_MAX", +} + +var FFToString = map[EvCode]string{ + FF_STATUS_STOPPED: "FF_STATUS_STOPPED", + FF_STATUS_PLAYING: "FF_STATUS_PLAYING", + // FF_STATUS_MAX: "FF_STATUS_MAX", // (FF_STATUS_PLAYING) + + FF_RUMBLE: "FF_RUMBLE", + FF_PERIODIC: "FF_PERIODIC", + FF_CONSTANT: "FF_CONSTANT", + FF_SPRING: "FF_SPRING", + FF_FRICTION: "FF_FRICTION", + FF_DAMPER: "FF_DAMPER", + FF_INERTIA: "FF_INERTIA", + FF_RAMP: "FF_RAMP", + + // FF_EFFECT_MIN: "FF_EFFECT_MIN", // (FF_RUMBLE) + // FF_EFFECT_MAX: "FF_EFFECT_MAX", // (FF_RAMP) + + FF_SQUARE: "FF_SQUARE", + FF_TRIANGLE: "FF_TRIANGLE", + FF_SINE: "FF_SINE", + FF_SAW_UP: "FF_SAW_UP", + FF_SAW_DOWN: "FF_SAW_DOWN", + FF_CUSTOM: "FF_CUSTOM", + + // FF_WAVEFORM_MIN: "FF_WAVEFORM_MIN", // (FF_SQUARE) + // FF_WAVEFORM_MAX: "FF_WAVEFORM_MAX", // (FF_CUSTOM) + + FF_GAIN: "FF_GAIN", + FF_AUTOCENTER: "FF_AUTOCENTER", + + // FF_MAX_EFFECTS: "FF_MAX_EFFECTS", // (FF_GAIN) + + FF_MAX: "FF_MAX", + FF_CNT: "FF_CNT", +} + +// +// Type from String +// + +var INPUTFromString = map[string]EvProp{ + "INPUT_PROP_POINTER": INPUT_PROP_POINTER, + "INPUT_PROP_DIRECT": INPUT_PROP_DIRECT, + "INPUT_PROP_BUTTONPAD": INPUT_PROP_BUTTONPAD, + "INPUT_PROP_SEMI_MT": INPUT_PROP_SEMI_MT, + "INPUT_PROP_TOPBUTTONPAD": INPUT_PROP_TOPBUTTONPAD, + "INPUT_PROP_POINTING_STICK": INPUT_PROP_POINTING_STICK, + "INPUT_PROP_ACCELEROMETER": INPUT_PROP_ACCELEROMETER, + + "INPUT_PROP_MAX": INPUT_PROP_MAX, + "INPUT_PROP_CNT": INPUT_PROP_CNT, +} + +var EVFromString = map[string]EvType{ + "EV_SYN": EV_SYN, + "EV_KEY": EV_KEY, + "EV_REL": EV_REL, + "EV_ABS": EV_ABS, + "EV_MSC": EV_MSC, + "EV_SW": EV_SW, + "EV_LED": EV_LED, + "EV_SND": EV_SND, + "EV_REP": EV_REP, + "EV_FF": EV_FF, + "EV_PWR": EV_PWR, + "EV_FF_STATUS": EV_FF_STATUS, + "EV_MAX": EV_MAX, + "EV_CNT": EV_CNT, +} + +var SYNFromString = map[string]EvCode{ + "SYN_REPORT": SYN_REPORT, + "SYN_CONFIG": SYN_CONFIG, + "SYN_MT_REPORT": SYN_MT_REPORT, + "SYN_DROPPED": SYN_DROPPED, + "SYN_MAX": SYN_MAX, + "SYN_CNT": SYN_CNT, +} + +var KEYFromString = map[string]EvCode{ + "KEY_RESERVED": KEY_RESERVED, + "KEY_ESC": KEY_ESC, + "KEY_1": KEY_1, + "KEY_2": KEY_2, + "KEY_3": KEY_3, + "KEY_4": KEY_4, + "KEY_5": KEY_5, + "KEY_6": KEY_6, + "KEY_7": KEY_7, + "KEY_8": KEY_8, + "KEY_9": KEY_9, + "KEY_0": KEY_0, + "KEY_MINUS": KEY_MINUS, + "KEY_EQUAL": KEY_EQUAL, + "KEY_BACKSPACE": KEY_BACKSPACE, + "KEY_TAB": KEY_TAB, + "KEY_Q": KEY_Q, + "KEY_W": KEY_W, + "KEY_E": KEY_E, + "KEY_R": KEY_R, + "KEY_T": KEY_T, + "KEY_Y": KEY_Y, + "KEY_U": KEY_U, + "KEY_I": KEY_I, + "KEY_O": KEY_O, + "KEY_P": KEY_P, + "KEY_LEFTBRACE": KEY_LEFTBRACE, + "KEY_RIGHTBRACE": KEY_RIGHTBRACE, + "KEY_ENTER": KEY_ENTER, + "KEY_LEFTCTRL": KEY_LEFTCTRL, + "KEY_A": KEY_A, + "KEY_S": KEY_S, + "KEY_D": KEY_D, + "KEY_F": KEY_F, + "KEY_G": KEY_G, + "KEY_H": KEY_H, + "KEY_J": KEY_J, + "KEY_K": KEY_K, + "KEY_L": KEY_L, + "KEY_SEMICOLON": KEY_SEMICOLON, + "KEY_APOSTROPHE": KEY_APOSTROPHE, + "KEY_GRAVE": KEY_GRAVE, + "KEY_LEFTSHIFT": KEY_LEFTSHIFT, + "KEY_BACKSLASH": KEY_BACKSLASH, + "KEY_Z": KEY_Z, + "KEY_X": KEY_X, + "KEY_C": KEY_C, + "KEY_V": KEY_V, + "KEY_B": KEY_B, + "KEY_N": KEY_N, + "KEY_M": KEY_M, + "KEY_COMMA": KEY_COMMA, + "KEY_DOT": KEY_DOT, + "KEY_SLASH": KEY_SLASH, + "KEY_RIGHTSHIFT": KEY_RIGHTSHIFT, + "KEY_KPASTERISK": KEY_KPASTERISK, + "KEY_LEFTALT": KEY_LEFTALT, + "KEY_SPACE": KEY_SPACE, + "KEY_CAPSLOCK": KEY_CAPSLOCK, + "KEY_F1": KEY_F1, + "KEY_F2": KEY_F2, + "KEY_F3": KEY_F3, + "KEY_F4": KEY_F4, + "KEY_F5": KEY_F5, + "KEY_F6": KEY_F6, + "KEY_F7": KEY_F7, + "KEY_F8": KEY_F8, + "KEY_F9": KEY_F9, + "KEY_F10": KEY_F10, + "KEY_NUMLOCK": KEY_NUMLOCK, + "KEY_SCROLLLOCK": KEY_SCROLLLOCK, + "KEY_KP7": KEY_KP7, + "KEY_KP8": KEY_KP8, + "KEY_KP9": KEY_KP9, + "KEY_KPMINUS": KEY_KPMINUS, + "KEY_KP4": KEY_KP4, + "KEY_KP5": KEY_KP5, + "KEY_KP6": KEY_KP6, + "KEY_KPPLUS": KEY_KPPLUS, + "KEY_KP1": KEY_KP1, + "KEY_KP2": KEY_KP2, + "KEY_KP3": KEY_KP3, + "KEY_KP0": KEY_KP0, + "KEY_KPDOT": KEY_KPDOT, + + "KEY_ZENKAKUHANKAKU": KEY_ZENKAKUHANKAKU, + "KEY_102ND": KEY_102ND, + "KEY_F11": KEY_F11, + "KEY_F12": KEY_F12, + "KEY_RO": KEY_RO, + "KEY_KATAKANA": KEY_KATAKANA, + "KEY_HIRAGANA": KEY_HIRAGANA, + "KEY_HENKAN": KEY_HENKAN, + "KEY_KATAKANAHIRAGANA": KEY_KATAKANAHIRAGANA, + "KEY_MUHENKAN": KEY_MUHENKAN, + "KEY_KPJPCOMMA": KEY_KPJPCOMMA, + "KEY_KPENTER": KEY_KPENTER, + "KEY_RIGHTCTRL": KEY_RIGHTCTRL, + "KEY_KPSLASH": KEY_KPSLASH, + "KEY_SYSRQ": KEY_SYSRQ, + "KEY_RIGHTALT": KEY_RIGHTALT, + "KEY_LINEFEED": KEY_LINEFEED, + "KEY_HOME": KEY_HOME, + "KEY_UP": KEY_UP, + "KEY_PAGEUP": KEY_PAGEUP, + "KEY_LEFT": KEY_LEFT, + "KEY_RIGHT": KEY_RIGHT, + "KEY_END": KEY_END, + "KEY_DOWN": KEY_DOWN, + "KEY_PAGEDOWN": KEY_PAGEDOWN, + "KEY_INSERT": KEY_INSERT, + "KEY_DELETE": KEY_DELETE, + "KEY_MACRO": KEY_MACRO, + "KEY_MUTE": KEY_MUTE, + "KEY_VOLUMEDOWN": KEY_VOLUMEDOWN, + "KEY_VOLUMEUP": KEY_VOLUMEUP, + "KEY_POWER": KEY_POWER, + "KEY_KPEQUAL": KEY_KPEQUAL, + "KEY_KPPLUSMINUS": KEY_KPPLUSMINUS, + "KEY_PAUSE": KEY_PAUSE, + "KEY_SCALE": KEY_SCALE, + + "KEY_KPCOMMA": KEY_KPCOMMA, + "KEY_HANGEUL": KEY_HANGEUL, + "KEY_HANGUEL": KEY_HANGUEL, + "KEY_HANJA": KEY_HANJA, + "KEY_YEN": KEY_YEN, + "KEY_LEFTMETA": KEY_LEFTMETA, + "KEY_RIGHTMETA": KEY_RIGHTMETA, + "KEY_COMPOSE": KEY_COMPOSE, + + "KEY_STOP": KEY_STOP, + "KEY_AGAIN": KEY_AGAIN, + "KEY_PROPS": KEY_PROPS, + "KEY_UNDO": KEY_UNDO, + "KEY_FRONT": KEY_FRONT, + "KEY_COPY": KEY_COPY, + "KEY_OPEN": KEY_OPEN, + "KEY_PASTE": KEY_PASTE, + "KEY_FIND": KEY_FIND, + "KEY_CUT": KEY_CUT, + "KEY_HELP": KEY_HELP, + "KEY_MENU": KEY_MENU, + "KEY_CALC": KEY_CALC, + "KEY_SETUP": KEY_SETUP, + "KEY_SLEEP": KEY_SLEEP, + "KEY_WAKEUP": KEY_WAKEUP, + "KEY_FILE": KEY_FILE, + "KEY_SENDFILE": KEY_SENDFILE, + "KEY_DELETEFILE": KEY_DELETEFILE, + "KEY_XFER": KEY_XFER, + "KEY_PROG1": KEY_PROG1, + "KEY_PROG2": KEY_PROG2, + "KEY_WWW": KEY_WWW, + "KEY_MSDOS": KEY_MSDOS, + "KEY_COFFEE": KEY_COFFEE, + "KEY_SCREENLOCK": KEY_SCREENLOCK, + "KEY_ROTATE_DISPLAY": KEY_ROTATE_DISPLAY, + "KEY_DIRECTION": KEY_DIRECTION, + "KEY_CYCLEWINDOWS": KEY_CYCLEWINDOWS, + "KEY_MAIL": KEY_MAIL, + "KEY_BOOKMARKS": KEY_BOOKMARKS, + "KEY_COMPUTER": KEY_COMPUTER, + "KEY_BACK": KEY_BACK, + "KEY_FORWARD": KEY_FORWARD, + "KEY_CLOSECD": KEY_CLOSECD, + "KEY_EJECTCD": KEY_EJECTCD, + "KEY_EJECTCLOSECD": KEY_EJECTCLOSECD, + "KEY_NEXTSONG": KEY_NEXTSONG, + "KEY_PLAYPAUSE": KEY_PLAYPAUSE, + "KEY_PREVIOUSSONG": KEY_PREVIOUSSONG, + "KEY_STOPCD": KEY_STOPCD, + "KEY_RECORD": KEY_RECORD, + "KEY_REWIND": KEY_REWIND, + "KEY_PHONE": KEY_PHONE, + "KEY_ISO": KEY_ISO, + "KEY_CONFIG": KEY_CONFIG, + "KEY_HOMEPAGE": KEY_HOMEPAGE, + "KEY_REFRESH": KEY_REFRESH, + "KEY_EXIT": KEY_EXIT, + "KEY_MOVE": KEY_MOVE, + "KEY_EDIT": KEY_EDIT, + "KEY_SCROLLUP": KEY_SCROLLUP, + "KEY_SCROLLDOWN": KEY_SCROLLDOWN, + "KEY_KPLEFTPAREN": KEY_KPLEFTPAREN, + "KEY_KPRIGHTPAREN": KEY_KPRIGHTPAREN, + "KEY_NEW": KEY_NEW, + "KEY_REDO": KEY_REDO, + + "KEY_F13": KEY_F13, + "KEY_F14": KEY_F14, + "KEY_F15": KEY_F15, + "KEY_F16": KEY_F16, + "KEY_F17": KEY_F17, + "KEY_F18": KEY_F18, + "KEY_F19": KEY_F19, + "KEY_F20": KEY_F20, + "KEY_F21": KEY_F21, + "KEY_F22": KEY_F22, + "KEY_F23": KEY_F23, + "KEY_F24": KEY_F24, + + "KEY_PLAYCD": KEY_PLAYCD, + "KEY_PAUSECD": KEY_PAUSECD, + "KEY_PROG3": KEY_PROG3, + "KEY_PROG4": KEY_PROG4, + "KEY_ALL_APPLICATIONS": KEY_ALL_APPLICATIONS, + "KEY_DASHBOARD": KEY_DASHBOARD, + "KEY_SUSPEND": KEY_SUSPEND, + "KEY_CLOSE": KEY_CLOSE, + "KEY_PLAY": KEY_PLAY, + "KEY_FASTFORWARD": KEY_FASTFORWARD, + "KEY_BASSBOOST": KEY_BASSBOOST, + "KEY_PRINT": KEY_PRINT, + "KEY_HP": KEY_HP, + "KEY_CAMERA": KEY_CAMERA, + "KEY_SOUND": KEY_SOUND, + "KEY_QUESTION": KEY_QUESTION, + "KEY_EMAIL": KEY_EMAIL, + "KEY_CHAT": KEY_CHAT, + "KEY_SEARCH": KEY_SEARCH, + "KEY_CONNECT": KEY_CONNECT, + "KEY_FINANCE": KEY_FINANCE, + "KEY_SPORT": KEY_SPORT, + "KEY_SHOP": KEY_SHOP, + "KEY_ALTERASE": KEY_ALTERASE, + "KEY_CANCEL": KEY_CANCEL, + "KEY_BRIGHTNESSDOWN": KEY_BRIGHTNESSDOWN, + "KEY_BRIGHTNESSUP": KEY_BRIGHTNESSUP, + "KEY_MEDIA": KEY_MEDIA, + + "KEY_SWITCHVIDEOMODE": KEY_SWITCHVIDEOMODE, + "KEY_KBDILLUMTOGGLE": KEY_KBDILLUMTOGGLE, + "KEY_KBDILLUMDOWN": KEY_KBDILLUMDOWN, + "KEY_KBDILLUMUP": KEY_KBDILLUMUP, + + "KEY_SEND": KEY_SEND, + "KEY_REPLY": KEY_REPLY, + "KEY_FORWARDMAIL": KEY_FORWARDMAIL, + "KEY_SAVE": KEY_SAVE, + "KEY_DOCUMENTS": KEY_DOCUMENTS, + + "KEY_BATTERY": KEY_BATTERY, + + "KEY_BLUETOOTH": KEY_BLUETOOTH, + "KEY_WLAN": KEY_WLAN, + "KEY_UWB": KEY_UWB, + + "KEY_UNKNOWN": KEY_UNKNOWN, + + "KEY_VIDEO_NEXT": KEY_VIDEO_NEXT, + "KEY_VIDEO_PREV": KEY_VIDEO_PREV, + "KEY_BRIGHTNESS_CYCLE": KEY_BRIGHTNESS_CYCLE, + "KEY_BRIGHTNESS_AUTO": KEY_BRIGHTNESS_AUTO, + "KEY_BRIGHTNESS_ZERO": KEY_BRIGHTNESS_ZERO, + "KEY_DISPLAY_OFF": KEY_DISPLAY_OFF, + + "KEY_WWAN": KEY_WWAN, + "KEY_WIMAX": KEY_WIMAX, + "KEY_RFKILL": KEY_RFKILL, + + "KEY_MICMUTE": KEY_MICMUTE, + + "BTN_MISC": BTN_MISC, + "BTN_0": BTN_0, + "BTN_1": BTN_1, + "BTN_2": BTN_2, + "BTN_3": BTN_3, + "BTN_4": BTN_4, + "BTN_5": BTN_5, + "BTN_6": BTN_6, + "BTN_7": BTN_7, + "BTN_8": BTN_8, + "BTN_9": BTN_9, + + "BTN_MOUSE": BTN_MOUSE, + "BTN_LEFT": BTN_LEFT, + "BTN_RIGHT": BTN_RIGHT, + "BTN_MIDDLE": BTN_MIDDLE, + "BTN_SIDE": BTN_SIDE, + "BTN_EXTRA": BTN_EXTRA, + "BTN_FORWARD": BTN_FORWARD, + "BTN_BACK": BTN_BACK, + "BTN_TASK": BTN_TASK, + + "BTN_JOYSTICK": BTN_JOYSTICK, + "BTN_TRIGGER": BTN_TRIGGER, + "BTN_THUMB": BTN_THUMB, + "BTN_THUMB2": BTN_THUMB2, + "BTN_TOP": BTN_TOP, + "BTN_TOP2": BTN_TOP2, + "BTN_PINKIE": BTN_PINKIE, + "BTN_BASE": BTN_BASE, + "BTN_BASE2": BTN_BASE2, + "BTN_BASE3": BTN_BASE3, + "BTN_BASE4": BTN_BASE4, + "BTN_BASE5": BTN_BASE5, + "BTN_BASE6": BTN_BASE6, + "BTN_DEAD": BTN_DEAD, + + "BTN_GAMEPAD": BTN_GAMEPAD, + "BTN_SOUTH": BTN_SOUTH, + "BTN_A": BTN_A, + "BTN_EAST": BTN_EAST, + "BTN_B": BTN_B, + "BTN_C": BTN_C, + "BTN_NORTH": BTN_NORTH, + "BTN_X": BTN_X, + "BTN_WEST": BTN_WEST, + "BTN_Y": BTN_Y, + "BTN_Z": BTN_Z, + "BTN_TL": BTN_TL, + "BTN_TR": BTN_TR, + "BTN_TL2": BTN_TL2, + "BTN_TR2": BTN_TR2, + "BTN_SELECT": BTN_SELECT, + "BTN_START": BTN_START, + "BTN_MODE": BTN_MODE, + "BTN_THUMBL": BTN_THUMBL, + "BTN_THUMBR": BTN_THUMBR, + + "BTN_DIGI": BTN_DIGI, + "BTN_TOOL_PEN": BTN_TOOL_PEN, + "BTN_TOOL_RUBBER": BTN_TOOL_RUBBER, + "BTN_TOOL_BRUSH": BTN_TOOL_BRUSH, + "BTN_TOOL_PENCIL": BTN_TOOL_PENCIL, + "BTN_TOOL_AIRBRUSH": BTN_TOOL_AIRBRUSH, + "BTN_TOOL_FINGER": BTN_TOOL_FINGER, + "BTN_TOOL_MOUSE": BTN_TOOL_MOUSE, + "BTN_TOOL_LENS": BTN_TOOL_LENS, + "BTN_TOOL_QUINTTAP": BTN_TOOL_QUINTTAP, + "BTN_STYLUS3": BTN_STYLUS3, + "BTN_TOUCH": BTN_TOUCH, + "BTN_STYLUS": BTN_STYLUS, + "BTN_STYLUS2": BTN_STYLUS2, + "BTN_TOOL_DOUBLETAP": BTN_TOOL_DOUBLETAP, + "BTN_TOOL_TRIPLETAP": BTN_TOOL_TRIPLETAP, + "BTN_TOOL_QUADTAP": BTN_TOOL_QUADTAP, + + "BTN_WHEEL": BTN_WHEEL, + "BTN_GEAR_DOWN": BTN_GEAR_DOWN, + "BTN_GEAR_UP": BTN_GEAR_UP, + + "KEY_OK": KEY_OK, + "KEY_SELECT": KEY_SELECT, + "KEY_GOTO": KEY_GOTO, + "KEY_CLEAR": KEY_CLEAR, + "KEY_POWER2": KEY_POWER2, + "KEY_OPTION": KEY_OPTION, + "KEY_INFO": KEY_INFO, + "KEY_TIME": KEY_TIME, + "KEY_VENDOR": KEY_VENDOR, + "KEY_ARCHIVE": KEY_ARCHIVE, + "KEY_PROGRAM": KEY_PROGRAM, + "KEY_CHANNEL": KEY_CHANNEL, + "KEY_FAVORITES": KEY_FAVORITES, + "KEY_EPG": KEY_EPG, + "KEY_PVR": KEY_PVR, + "KEY_MHP": KEY_MHP, + "KEY_LANGUAGE": KEY_LANGUAGE, + "KEY_TITLE": KEY_TITLE, + "KEY_SUBTITLE": KEY_SUBTITLE, + "KEY_ANGLE": KEY_ANGLE, + "KEY_FULL_SCREEN": KEY_FULL_SCREEN, + "KEY_ZOOM": KEY_ZOOM, + "KEY_MODE": KEY_MODE, + "KEY_KEYBOARD": KEY_KEYBOARD, + "KEY_ASPECT_RATIO": KEY_ASPECT_RATIO, + "KEY_SCREEN": KEY_SCREEN, + "KEY_PC": KEY_PC, + "KEY_TV": KEY_TV, + "KEY_TV2": KEY_TV2, + "KEY_VCR": KEY_VCR, + "KEY_VCR2": KEY_VCR2, + "KEY_SAT": KEY_SAT, + "KEY_SAT2": KEY_SAT2, + "KEY_CD": KEY_CD, + "KEY_TAPE": KEY_TAPE, + "KEY_RADIO": KEY_RADIO, + "KEY_TUNER": KEY_TUNER, + "KEY_PLAYER": KEY_PLAYER, + "KEY_TEXT": KEY_TEXT, + "KEY_DVD": KEY_DVD, + "KEY_AUX": KEY_AUX, + "KEY_MP3": KEY_MP3, + "KEY_AUDIO": KEY_AUDIO, + "KEY_VIDEO": KEY_VIDEO, + "KEY_DIRECTORY": KEY_DIRECTORY, + "KEY_LIST": KEY_LIST, + "KEY_MEMO": KEY_MEMO, + "KEY_CALENDAR": KEY_CALENDAR, + "KEY_RED": KEY_RED, + "KEY_GREEN": KEY_GREEN, + "KEY_YELLOW": KEY_YELLOW, + "KEY_BLUE": KEY_BLUE, + "KEY_CHANNELUP": KEY_CHANNELUP, + "KEY_CHANNELDOWN": KEY_CHANNELDOWN, + "KEY_FIRST": KEY_FIRST, + "KEY_LAST": KEY_LAST, + "KEY_AB": KEY_AB, + "KEY_NEXT": KEY_NEXT, + "KEY_RESTART": KEY_RESTART, + "KEY_SLOW": KEY_SLOW, + "KEY_SHUFFLE": KEY_SHUFFLE, + "KEY_BREAK": KEY_BREAK, + "KEY_PREVIOUS": KEY_PREVIOUS, + "KEY_DIGITS": KEY_DIGITS, + "KEY_TEEN": KEY_TEEN, + "KEY_TWEN": KEY_TWEN, + "KEY_VIDEOPHONE": KEY_VIDEOPHONE, + "KEY_GAMES": KEY_GAMES, + "KEY_ZOOMIN": KEY_ZOOMIN, + "KEY_ZOOMOUT": KEY_ZOOMOUT, + "KEY_ZOOMRESET": KEY_ZOOMRESET, + "KEY_WORDPROCESSOR": KEY_WORDPROCESSOR, + "KEY_EDITOR": KEY_EDITOR, + "KEY_SPREADSHEET": KEY_SPREADSHEET, + "KEY_GRAPHICSEDITOR": KEY_GRAPHICSEDITOR, + "KEY_PRESENTATION": KEY_PRESENTATION, + "KEY_DATABASE": KEY_DATABASE, + "KEY_NEWS": KEY_NEWS, + "KEY_VOICEMAIL": KEY_VOICEMAIL, + "KEY_ADDRESSBOOK": KEY_ADDRESSBOOK, + "KEY_MESSENGER": KEY_MESSENGER, + "KEY_DISPLAYTOGGLE": KEY_DISPLAYTOGGLE, + "KEY_BRIGHTNESS_TOGGLE": KEY_BRIGHTNESS_TOGGLE, + "KEY_SPELLCHECK": KEY_SPELLCHECK, + "KEY_LOGOFF": KEY_LOGOFF, + + "KEY_DOLLAR": KEY_DOLLAR, + "KEY_EURO": KEY_EURO, + + "KEY_FRAMEBACK": KEY_FRAMEBACK, + "KEY_FRAMEFORWARD": KEY_FRAMEFORWARD, + "KEY_CONTEXT_MENU": KEY_CONTEXT_MENU, + "KEY_MEDIA_REPEAT": KEY_MEDIA_REPEAT, + "KEY_10CHANNELSUP": KEY_10CHANNELSUP, + "KEY_10CHANNELSDOWN": KEY_10CHANNELSDOWN, + "KEY_IMAGES": KEY_IMAGES, + "KEY_NOTIFICATION_CENTER": KEY_NOTIFICATION_CENTER, + "KEY_PICKUP_PHONE": KEY_PICKUP_PHONE, + "KEY_HANGUP_PHONE": KEY_HANGUP_PHONE, + + "KEY_DEL_EOL": KEY_DEL_EOL, + "KEY_DEL_EOS": KEY_DEL_EOS, + "KEY_INS_LINE": KEY_INS_LINE, + "KEY_DEL_LINE": KEY_DEL_LINE, + + "KEY_FN": KEY_FN, + "KEY_FN_ESC": KEY_FN_ESC, + "KEY_FN_F1": KEY_FN_F1, + "KEY_FN_F2": KEY_FN_F2, + "KEY_FN_F3": KEY_FN_F3, + "KEY_FN_F4": KEY_FN_F4, + "KEY_FN_F5": KEY_FN_F5, + "KEY_FN_F6": KEY_FN_F6, + "KEY_FN_F7": KEY_FN_F7, + "KEY_FN_F8": KEY_FN_F8, + "KEY_FN_F9": KEY_FN_F9, + "KEY_FN_F10": KEY_FN_F10, + "KEY_FN_F11": KEY_FN_F11, + "KEY_FN_F12": KEY_FN_F12, + "KEY_FN_1": KEY_FN_1, + "KEY_FN_2": KEY_FN_2, + "KEY_FN_D": KEY_FN_D, + "KEY_FN_E": KEY_FN_E, + "KEY_FN_F": KEY_FN_F, + "KEY_FN_S": KEY_FN_S, + "KEY_FN_B": KEY_FN_B, + "KEY_FN_RIGHT_SHIFT": KEY_FN_RIGHT_SHIFT, + + "KEY_BRL_DOT1": KEY_BRL_DOT1, + "KEY_BRL_DOT2": KEY_BRL_DOT2, + "KEY_BRL_DOT3": KEY_BRL_DOT3, + "KEY_BRL_DOT4": KEY_BRL_DOT4, + "KEY_BRL_DOT5": KEY_BRL_DOT5, + "KEY_BRL_DOT6": KEY_BRL_DOT6, + "KEY_BRL_DOT7": KEY_BRL_DOT7, + "KEY_BRL_DOT8": KEY_BRL_DOT8, + "KEY_BRL_DOT9": KEY_BRL_DOT9, + "KEY_BRL_DOT10": KEY_BRL_DOT10, + + "KEY_NUMERIC_0": KEY_NUMERIC_0, + "KEY_NUMERIC_1": KEY_NUMERIC_1, + "KEY_NUMERIC_2": KEY_NUMERIC_2, + "KEY_NUMERIC_3": KEY_NUMERIC_3, + "KEY_NUMERIC_4": KEY_NUMERIC_4, + "KEY_NUMERIC_5": KEY_NUMERIC_5, + "KEY_NUMERIC_6": KEY_NUMERIC_6, + "KEY_NUMERIC_7": KEY_NUMERIC_7, + "KEY_NUMERIC_8": KEY_NUMERIC_8, + "KEY_NUMERIC_9": KEY_NUMERIC_9, + "KEY_NUMERIC_STAR": KEY_NUMERIC_STAR, + "KEY_NUMERIC_POUND": KEY_NUMERIC_POUND, + "KEY_NUMERIC_A": KEY_NUMERIC_A, + "KEY_NUMERIC_B": KEY_NUMERIC_B, + "KEY_NUMERIC_C": KEY_NUMERIC_C, + "KEY_NUMERIC_D": KEY_NUMERIC_D, + + "KEY_CAMERA_FOCUS": KEY_CAMERA_FOCUS, + "KEY_WPS_BUTTON": KEY_WPS_BUTTON, + + "KEY_TOUCHPAD_TOGGLE": KEY_TOUCHPAD_TOGGLE, + "KEY_TOUCHPAD_ON": KEY_TOUCHPAD_ON, + "KEY_TOUCHPAD_OFF": KEY_TOUCHPAD_OFF, + + "KEY_CAMERA_ZOOMIN": KEY_CAMERA_ZOOMIN, + "KEY_CAMERA_ZOOMOUT": KEY_CAMERA_ZOOMOUT, + "KEY_CAMERA_UP": KEY_CAMERA_UP, + "KEY_CAMERA_DOWN": KEY_CAMERA_DOWN, + "KEY_CAMERA_LEFT": KEY_CAMERA_LEFT, + "KEY_CAMERA_RIGHT": KEY_CAMERA_RIGHT, + + "KEY_ATTENDANT_ON": KEY_ATTENDANT_ON, + "KEY_ATTENDANT_OFF": KEY_ATTENDANT_OFF, + "KEY_ATTENDANT_TOGGLE": KEY_ATTENDANT_TOGGLE, + "KEY_LIGHTS_TOGGLE": KEY_LIGHTS_TOGGLE, + + "BTN_DPAD_UP": BTN_DPAD_UP, + "BTN_DPAD_DOWN": BTN_DPAD_DOWN, + "BTN_DPAD_LEFT": BTN_DPAD_LEFT, + "BTN_DPAD_RIGHT": BTN_DPAD_RIGHT, + + "KEY_ALS_TOGGLE": KEY_ALS_TOGGLE, + "KEY_ROTATE_LOCK_TOGGLE": KEY_ROTATE_LOCK_TOGGLE, + + "KEY_BUTTONCONFIG": KEY_BUTTONCONFIG, + "KEY_TASKMANAGER": KEY_TASKMANAGER, + "KEY_JOURNAL": KEY_JOURNAL, + "KEY_CONTROLPANEL": KEY_CONTROLPANEL, + "KEY_APPSELECT": KEY_APPSELECT, + "KEY_SCREENSAVER": KEY_SCREENSAVER, + "KEY_VOICECOMMAND": KEY_VOICECOMMAND, + "KEY_ASSISTANT": KEY_ASSISTANT, + "KEY_KBD_LAYOUT_NEXT": KEY_KBD_LAYOUT_NEXT, + "KEY_EMOJI_PICKER": KEY_EMOJI_PICKER, + "KEY_DICTATE": KEY_DICTATE, + + "KEY_BRIGHTNESS_MIN": KEY_BRIGHTNESS_MIN, + "KEY_BRIGHTNESS_MAX": KEY_BRIGHTNESS_MAX, + + "KEY_KBDINPUTASSIST_PREV": KEY_KBDINPUTASSIST_PREV, + "KEY_KBDINPUTASSIST_NEXT": KEY_KBDINPUTASSIST_NEXT, + "KEY_KBDINPUTASSIST_PREVGROUP": KEY_KBDINPUTASSIST_PREVGROUP, + "KEY_KBDINPUTASSIST_NEXTGROUP": KEY_KBDINPUTASSIST_NEXTGROUP, + "KEY_KBDINPUTASSIST_ACCEPT": KEY_KBDINPUTASSIST_ACCEPT, + "KEY_KBDINPUTASSIST_CANCEL": KEY_KBDINPUTASSIST_CANCEL, + + "KEY_RIGHT_UP": KEY_RIGHT_UP, + "KEY_RIGHT_DOWN": KEY_RIGHT_DOWN, + "KEY_LEFT_UP": KEY_LEFT_UP, + "KEY_LEFT_DOWN": KEY_LEFT_DOWN, + + "KEY_ROOT_MENU": KEY_ROOT_MENU, + + "KEY_MEDIA_TOP_MENU": KEY_MEDIA_TOP_MENU, + "KEY_NUMERIC_11": KEY_NUMERIC_11, + "KEY_NUMERIC_12": KEY_NUMERIC_12, + + "KEY_AUDIO_DESC": KEY_AUDIO_DESC, + "KEY_3D_MODE": KEY_3D_MODE, + "KEY_NEXT_FAVORITE": KEY_NEXT_FAVORITE, + "KEY_STOP_RECORD": KEY_STOP_RECORD, + "KEY_PAUSE_RECORD": KEY_PAUSE_RECORD, + "KEY_VOD": KEY_VOD, + "KEY_UNMUTE": KEY_UNMUTE, + "KEY_FASTREVERSE": KEY_FASTREVERSE, + "KEY_SLOWREVERSE": KEY_SLOWREVERSE, + + "KEY_DATA": KEY_DATA, + "KEY_ONSCREEN_KEYBOARD": KEY_ONSCREEN_KEYBOARD, + + "KEY_PRIVACY_SCREEN_TOGGLE": KEY_PRIVACY_SCREEN_TOGGLE, + + "KEY_SELECTIVE_SCREENSHOT": KEY_SELECTIVE_SCREENSHOT, + + "KEY_MACRO1": KEY_MACRO1, + "KEY_MACRO2": KEY_MACRO2, + "KEY_MACRO3": KEY_MACRO3, + "KEY_MACRO4": KEY_MACRO4, + "KEY_MACRO5": KEY_MACRO5, + "KEY_MACRO6": KEY_MACRO6, + "KEY_MACRO7": KEY_MACRO7, + "KEY_MACRO8": KEY_MACRO8, + "KEY_MACRO9": KEY_MACRO9, + "KEY_MACRO10": KEY_MACRO10, + "KEY_MACRO11": KEY_MACRO11, + "KEY_MACRO12": KEY_MACRO12, + "KEY_MACRO13": KEY_MACRO13, + "KEY_MACRO14": KEY_MACRO14, + "KEY_MACRO15": KEY_MACRO15, + "KEY_MACRO16": KEY_MACRO16, + "KEY_MACRO17": KEY_MACRO17, + "KEY_MACRO18": KEY_MACRO18, + "KEY_MACRO19": KEY_MACRO19, + "KEY_MACRO20": KEY_MACRO20, + "KEY_MACRO21": KEY_MACRO21, + "KEY_MACRO22": KEY_MACRO22, + "KEY_MACRO23": KEY_MACRO23, + "KEY_MACRO24": KEY_MACRO24, + "KEY_MACRO25": KEY_MACRO25, + "KEY_MACRO26": KEY_MACRO26, + "KEY_MACRO27": KEY_MACRO27, + "KEY_MACRO28": KEY_MACRO28, + "KEY_MACRO29": KEY_MACRO29, + "KEY_MACRO30": KEY_MACRO30, + + "KEY_MACRO_RECORD_START": KEY_MACRO_RECORD_START, + "KEY_MACRO_RECORD_STOP": KEY_MACRO_RECORD_STOP, + "KEY_MACRO_PRESET_CYCLE": KEY_MACRO_PRESET_CYCLE, + "KEY_MACRO_PRESET1": KEY_MACRO_PRESET1, + "KEY_MACRO_PRESET2": KEY_MACRO_PRESET2, + "KEY_MACRO_PRESET3": KEY_MACRO_PRESET3, + + "KEY_KBD_LCD_MENU1": KEY_KBD_LCD_MENU1, + "KEY_KBD_LCD_MENU2": KEY_KBD_LCD_MENU2, + "KEY_KBD_LCD_MENU3": KEY_KBD_LCD_MENU3, + "KEY_KBD_LCD_MENU4": KEY_KBD_LCD_MENU4, + "KEY_KBD_LCD_MENU5": KEY_KBD_LCD_MENU5, + + "BTN_TRIGGER_HAPPY": BTN_TRIGGER_HAPPY, + "BTN_TRIGGER_HAPPY1": BTN_TRIGGER_HAPPY1, + "BTN_TRIGGER_HAPPY2": BTN_TRIGGER_HAPPY2, + "BTN_TRIGGER_HAPPY3": BTN_TRIGGER_HAPPY3, + "BTN_TRIGGER_HAPPY4": BTN_TRIGGER_HAPPY4, + "BTN_TRIGGER_HAPPY5": BTN_TRIGGER_HAPPY5, + "BTN_TRIGGER_HAPPY6": BTN_TRIGGER_HAPPY6, + "BTN_TRIGGER_HAPPY7": BTN_TRIGGER_HAPPY7, + "BTN_TRIGGER_HAPPY8": BTN_TRIGGER_HAPPY8, + "BTN_TRIGGER_HAPPY9": BTN_TRIGGER_HAPPY9, + "BTN_TRIGGER_HAPPY10": BTN_TRIGGER_HAPPY10, + "BTN_TRIGGER_HAPPY11": BTN_TRIGGER_HAPPY11, + "BTN_TRIGGER_HAPPY12": BTN_TRIGGER_HAPPY12, + "BTN_TRIGGER_HAPPY13": BTN_TRIGGER_HAPPY13, + "BTN_TRIGGER_HAPPY14": BTN_TRIGGER_HAPPY14, + "BTN_TRIGGER_HAPPY15": BTN_TRIGGER_HAPPY15, + "BTN_TRIGGER_HAPPY16": BTN_TRIGGER_HAPPY16, + "BTN_TRIGGER_HAPPY17": BTN_TRIGGER_HAPPY17, + "BTN_TRIGGER_HAPPY18": BTN_TRIGGER_HAPPY18, + "BTN_TRIGGER_HAPPY19": BTN_TRIGGER_HAPPY19, + "BTN_TRIGGER_HAPPY20": BTN_TRIGGER_HAPPY20, + "BTN_TRIGGER_HAPPY21": BTN_TRIGGER_HAPPY21, + "BTN_TRIGGER_HAPPY22": BTN_TRIGGER_HAPPY22, + "BTN_TRIGGER_HAPPY23": BTN_TRIGGER_HAPPY23, + "BTN_TRIGGER_HAPPY24": BTN_TRIGGER_HAPPY24, + "BTN_TRIGGER_HAPPY25": BTN_TRIGGER_HAPPY25, + "BTN_TRIGGER_HAPPY26": BTN_TRIGGER_HAPPY26, + "BTN_TRIGGER_HAPPY27": BTN_TRIGGER_HAPPY27, + "BTN_TRIGGER_HAPPY28": BTN_TRIGGER_HAPPY28, + "BTN_TRIGGER_HAPPY29": BTN_TRIGGER_HAPPY29, + "BTN_TRIGGER_HAPPY30": BTN_TRIGGER_HAPPY30, + "BTN_TRIGGER_HAPPY31": BTN_TRIGGER_HAPPY31, + "BTN_TRIGGER_HAPPY32": BTN_TRIGGER_HAPPY32, + "BTN_TRIGGER_HAPPY33": BTN_TRIGGER_HAPPY33, + "BTN_TRIGGER_HAPPY34": BTN_TRIGGER_HAPPY34, + "BTN_TRIGGER_HAPPY35": BTN_TRIGGER_HAPPY35, + "BTN_TRIGGER_HAPPY36": BTN_TRIGGER_HAPPY36, + "BTN_TRIGGER_HAPPY37": BTN_TRIGGER_HAPPY37, + "BTN_TRIGGER_HAPPY38": BTN_TRIGGER_HAPPY38, + "BTN_TRIGGER_HAPPY39": BTN_TRIGGER_HAPPY39, + "BTN_TRIGGER_HAPPY40": BTN_TRIGGER_HAPPY40, + + "KEY_MIN_INTERESTING": KEY_MIN_INTERESTING, + "KEY_MAX": KEY_MAX, + "KEY_CNT": KEY_CNT, +} + +var RELFromString = map[string]EvCode{ + "REL_X": REL_X, + "REL_Y": REL_Y, + "REL_Z": REL_Z, + "REL_RX": REL_RX, + "REL_RY": REL_RY, + "REL_RZ": REL_RZ, + "REL_HWHEEL": REL_HWHEEL, + "REL_DIAL": REL_DIAL, + "REL_WHEEL": REL_WHEEL, + "REL_MISC": REL_MISC, + + "REL_RESERVED": REL_RESERVED, + "REL_WHEEL_HI_RES": REL_WHEEL_HI_RES, + "REL_HWHEEL_HI_RES": REL_HWHEEL_HI_RES, + "REL_MAX": REL_MAX, + "REL_CNT": REL_CNT, +} + +var ABSFromString = map[string]EvCode{ + "ABS_X": ABS_X, + "ABS_Y": ABS_Y, + "ABS_Z": ABS_Z, + "ABS_RX": ABS_RX, + "ABS_RY": ABS_RY, + "ABS_RZ": ABS_RZ, + "ABS_THROTTLE": ABS_THROTTLE, + "ABS_RUDDER": ABS_RUDDER, + "ABS_WHEEL": ABS_WHEEL, + "ABS_GAS": ABS_GAS, + "ABS_BRAKE": ABS_BRAKE, + "ABS_HAT0X": ABS_HAT0X, + "ABS_HAT0Y": ABS_HAT0Y, + "ABS_HAT1X": ABS_HAT1X, + "ABS_HAT1Y": ABS_HAT1Y, + "ABS_HAT2X": ABS_HAT2X, + "ABS_HAT2Y": ABS_HAT2Y, + "ABS_HAT3X": ABS_HAT3X, + "ABS_HAT3Y": ABS_HAT3Y, + "ABS_PRESSURE": ABS_PRESSURE, + "ABS_DISTANCE": ABS_DISTANCE, + "ABS_TILT_X": ABS_TILT_X, + "ABS_TILT_Y": ABS_TILT_Y, + "ABS_TOOL_WIDTH": ABS_TOOL_WIDTH, + + "ABS_VOLUME": ABS_VOLUME, + + "ABS_MISC": ABS_MISC, + + "ABS_RESERVED": ABS_RESERVED, + + "ABS_MT_SLOT": ABS_MT_SLOT, + "ABS_MT_TOUCH_MAJOR": ABS_MT_TOUCH_MAJOR, + "ABS_MT_TOUCH_MINOR": ABS_MT_TOUCH_MINOR, + "ABS_MT_WIDTH_MAJOR": ABS_MT_WIDTH_MAJOR, + "ABS_MT_WIDTH_MINOR": ABS_MT_WIDTH_MINOR, + "ABS_MT_ORIENTATION": ABS_MT_ORIENTATION, + "ABS_MT_POSITION_X": ABS_MT_POSITION_X, + "ABS_MT_POSITION_Y": ABS_MT_POSITION_Y, + "ABS_MT_TOOL_TYPE": ABS_MT_TOOL_TYPE, + "ABS_MT_BLOB_ID": ABS_MT_BLOB_ID, + "ABS_MT_TRACKING_ID": ABS_MT_TRACKING_ID, + "ABS_MT_PRESSURE": ABS_MT_PRESSURE, + "ABS_MT_DISTANCE": ABS_MT_DISTANCE, + "ABS_MT_TOOL_X": ABS_MT_TOOL_X, + "ABS_MT_TOOL_Y": ABS_MT_TOOL_Y, + + "ABS_MAX": ABS_MAX, + "ABS_CNT": ABS_CNT, +} + +var SWFromString = map[string]EvCode{ + "SW_LID": SW_LID, + "SW_TABLET_MODE": SW_TABLET_MODE, + "SW_HEADPHONE_INSERT": SW_HEADPHONE_INSERT, + "SW_RFKILL_ALL": SW_RFKILL_ALL, + "SW_RADIO": SW_RADIO, + "SW_MICROPHONE_INSERT": SW_MICROPHONE_INSERT, + "SW_DOCK": SW_DOCK, + "SW_LINEOUT_INSERT": SW_LINEOUT_INSERT, + "SW_JACK_PHYSICAL_INSERT": SW_JACK_PHYSICAL_INSERT, + "SW_VIDEOOUT_INSERT": SW_VIDEOOUT_INSERT, + "SW_CAMERA_LENS_COVER": SW_CAMERA_LENS_COVER, + "SW_KEYPAD_SLIDE": SW_KEYPAD_SLIDE, + "SW_FRONT_PROXIMITY": SW_FRONT_PROXIMITY, + "SW_ROTATE_LOCK": SW_ROTATE_LOCK, + "SW_LINEIN_INSERT": SW_LINEIN_INSERT, + "SW_MUTE_DEVICE": SW_MUTE_DEVICE, + "SW_PEN_INSERTED": SW_PEN_INSERTED, + "SW_MACHINE_COVER": SW_MACHINE_COVER, + "SW_MAX": SW_MAX, + "SW_CNT": SW_CNT, +} + +var MSCFromString = map[string]EvCode{ + "MSC_SERIAL": MSC_SERIAL, + "MSC_PULSELED": MSC_PULSELED, + "MSC_GESTURE": MSC_GESTURE, + "MSC_RAW": MSC_RAW, + "MSC_SCAN": MSC_SCAN, + "MSC_TIMESTAMP": MSC_TIMESTAMP, + "MSC_MAX": MSC_MAX, + "MSC_CNT": MSC_CNT, +} + +var LEDFromString = map[string]EvCode{ + "LED_NUML": LED_NUML, + "LED_CAPSL": LED_CAPSL, + "LED_SCROLLL": LED_SCROLLL, + "LED_COMPOSE": LED_COMPOSE, + "LED_KANA": LED_KANA, + "LED_SLEEP": LED_SLEEP, + "LED_SUSPEND": LED_SUSPEND, + "LED_MUTE": LED_MUTE, + "LED_MISC": LED_MISC, + "LED_MAIL": LED_MAIL, + "LED_CHARGING": LED_CHARGING, + "LED_MAX": LED_MAX, + "LED_CNT": LED_CNT, +} + +var REPFromString = map[string]EvCode{ + "REP_DELAY": REP_DELAY, + "REP_PERIOD": REP_PERIOD, + "REP_MAX": REP_MAX, + "REP_CNT": REP_CNT, +} + +var SNDFromString = map[string]EvCode{ + "SND_CLICK": SND_CLICK, + "SND_BELL": SND_BELL, + "SND_TONE": SND_TONE, + "SND_MAX": SND_MAX, + "SND_CNT": SND_CNT, +} + +var IDFromString = map[string]EvCode{ + "ID_BUS": ID_BUS, + "ID_VENDOR": ID_VENDOR, + "ID_PRODUCT": ID_PRODUCT, + "ID_VERSION": ID_VERSION, +} + +var BUSFromString = map[string]EvCode{ + "BUS_PCI": BUS_PCI, + "BUS_ISAPNP": BUS_ISAPNP, + "BUS_USB": BUS_USB, + "BUS_HIL": BUS_HIL, + "BUS_BLUETOOTH": BUS_BLUETOOTH, + "BUS_VIRTUAL": BUS_VIRTUAL, + + "BUS_ISA": BUS_ISA, + "BUS_I8042": BUS_I8042, + "BUS_XTKBD": BUS_XTKBD, + "BUS_RS232": BUS_RS232, + "BUS_GAMEPORT": BUS_GAMEPORT, + "BUS_PARPORT": BUS_PARPORT, + "BUS_AMIGA": BUS_AMIGA, + "BUS_ADB": BUS_ADB, + "BUS_I2C": BUS_I2C, + "BUS_HOST": BUS_HOST, + "BUS_GSC": BUS_GSC, + "BUS_ATARI": BUS_ATARI, + "BUS_SPI": BUS_SPI, + "BUS_RMI": BUS_RMI, + "BUS_CEC": BUS_CEC, + "BUS_INTEL_ISHTP": BUS_INTEL_ISHTP, +} + +var MTFromString = map[string]EvCode{ + "MT_TOOL_FINGER": MT_TOOL_FINGER, + "MT_TOOL_PEN": MT_TOOL_PEN, + "MT_TOOL_PALM": MT_TOOL_PALM, + "MT_TOOL_DIAL": MT_TOOL_DIAL, + "MT_TOOL_MAX": MT_TOOL_MAX, +} + +var FFFromString = map[string]EvCode{ + "FF_STATUS_STOPPED": FF_STATUS_STOPPED, + "FF_STATUS_PLAYING": FF_STATUS_PLAYING, + "FF_STATUS_MAX": FF_STATUS_MAX, + + "FF_RUMBLE": FF_RUMBLE, + "FF_PERIODIC": FF_PERIODIC, + "FF_CONSTANT": FF_CONSTANT, + "FF_SPRING": FF_SPRING, + "FF_FRICTION": FF_FRICTION, + "FF_DAMPER": FF_DAMPER, + "FF_INERTIA": FF_INERTIA, + "FF_RAMP": FF_RAMP, + + "FF_EFFECT_MIN": FF_EFFECT_MIN, + "FF_EFFECT_MAX": FF_EFFECT_MAX, + + "FF_SQUARE": FF_SQUARE, + "FF_TRIANGLE": FF_TRIANGLE, + "FF_SINE": FF_SINE, + "FF_SAW_UP": FF_SAW_UP, + "FF_SAW_DOWN": FF_SAW_DOWN, + "FF_CUSTOM": FF_CUSTOM, + + "FF_WAVEFORM_MIN": FF_WAVEFORM_MIN, + "FF_WAVEFORM_MAX": FF_WAVEFORM_MAX, + + "FF_GAIN": FF_GAIN, + "FF_AUTOCENTER": FF_AUTOCENTER, + + "FF_MAX_EFFECTS": FF_MAX_EFFECTS, + + "FF_MAX": FF_MAX, + "FF_CNT": FF_CNT, +} + +// +// Type Names (informative debug use only) +// + +var INPUTNames = map[EvProp]string{ + INPUT_PROP_POINTER: "INPUT_PROP_POINTER", + INPUT_PROP_DIRECT: "INPUT_PROP_DIRECT", + INPUT_PROP_BUTTONPAD: "INPUT_PROP_BUTTONPAD", + INPUT_PROP_SEMI_MT: "INPUT_PROP_SEMI_MT", + INPUT_PROP_TOPBUTTONPAD: "INPUT_PROP_TOPBUTTONPAD", + INPUT_PROP_POINTING_STICK: "INPUT_PROP_POINTING_STICK", + INPUT_PROP_ACCELEROMETER: "INPUT_PROP_ACCELEROMETER", + + INPUT_PROP_MAX: "INPUT_PROP_MAX", + INPUT_PROP_CNT: "INPUT_PROP_CNT", +} + +var EVNames = map[EvType]string{ + EV_SYN: "EV_SYN", + EV_KEY: "EV_KEY", + EV_REL: "EV_REL", + EV_ABS: "EV_ABS", + EV_MSC: "EV_MSC", + EV_SW: "EV_SW", + EV_LED: "EV_LED", + EV_SND: "EV_SND", + EV_REP: "EV_REP", + EV_FF: "EV_FF", + EV_PWR: "EV_PWR", + EV_FF_STATUS: "EV_FF_STATUS", + EV_MAX: "EV_MAX", + EV_CNT: "EV_CNT", +} + +var SYNNames = map[EvCode]string{ + SYN_REPORT: "SYN_REPORT", + SYN_CONFIG: "SYN_CONFIG", + SYN_MT_REPORT: "SYN_MT_REPORT", + SYN_DROPPED: "SYN_DROPPED", + SYN_MAX: "SYN_MAX", + SYN_CNT: "SYN_CNT", +} + +var KEYNames = map[EvCode]string{ + KEY_RESERVED: "KEY_RESERVED", + KEY_ESC: "KEY_ESC", + KEY_1: "KEY_1", + KEY_2: "KEY_2", + KEY_3: "KEY_3", + KEY_4: "KEY_4", + KEY_5: "KEY_5", + KEY_6: "KEY_6", + KEY_7: "KEY_7", + KEY_8: "KEY_8", + KEY_9: "KEY_9", + KEY_0: "KEY_0", + KEY_MINUS: "KEY_MINUS", + KEY_EQUAL: "KEY_EQUAL", + KEY_BACKSPACE: "KEY_BACKSPACE", + KEY_TAB: "KEY_TAB", + KEY_Q: "KEY_Q", + KEY_W: "KEY_W", + KEY_E: "KEY_E", + KEY_R: "KEY_R", + KEY_T: "KEY_T", + KEY_Y: "KEY_Y", + KEY_U: "KEY_U", + KEY_I: "KEY_I", + KEY_O: "KEY_O", + KEY_P: "KEY_P", + KEY_LEFTBRACE: "KEY_LEFTBRACE", + KEY_RIGHTBRACE: "KEY_RIGHTBRACE", + KEY_ENTER: "KEY_ENTER", + KEY_LEFTCTRL: "KEY_LEFTCTRL", + KEY_A: "KEY_A", + KEY_S: "KEY_S", + KEY_D: "KEY_D", + KEY_F: "KEY_F", + KEY_G: "KEY_G", + KEY_H: "KEY_H", + KEY_J: "KEY_J", + KEY_K: "KEY_K", + KEY_L: "KEY_L", + KEY_SEMICOLON: "KEY_SEMICOLON", + KEY_APOSTROPHE: "KEY_APOSTROPHE", + KEY_GRAVE: "KEY_GRAVE", + KEY_LEFTSHIFT: "KEY_LEFTSHIFT", + KEY_BACKSLASH: "KEY_BACKSLASH", + KEY_Z: "KEY_Z", + KEY_X: "KEY_X", + KEY_C: "KEY_C", + KEY_V: "KEY_V", + KEY_B: "KEY_B", + KEY_N: "KEY_N", + KEY_M: "KEY_M", + KEY_COMMA: "KEY_COMMA", + KEY_DOT: "KEY_DOT", + KEY_SLASH: "KEY_SLASH", + KEY_RIGHTSHIFT: "KEY_RIGHTSHIFT", + KEY_KPASTERISK: "KEY_KPASTERISK", + KEY_LEFTALT: "KEY_LEFTALT", + KEY_SPACE: "KEY_SPACE", + KEY_CAPSLOCK: "KEY_CAPSLOCK", + KEY_F1: "KEY_F1", + KEY_F2: "KEY_F2", + KEY_F3: "KEY_F3", + KEY_F4: "KEY_F4", + KEY_F5: "KEY_F5", + KEY_F6: "KEY_F6", + KEY_F7: "KEY_F7", + KEY_F8: "KEY_F8", + KEY_F9: "KEY_F9", + KEY_F10: "KEY_F10", + KEY_NUMLOCK: "KEY_NUMLOCK", + KEY_SCROLLLOCK: "KEY_SCROLLLOCK", + KEY_KP7: "KEY_KP7", + KEY_KP8: "KEY_KP8", + KEY_KP9: "KEY_KP9", + KEY_KPMINUS: "KEY_KPMINUS", + KEY_KP4: "KEY_KP4", + KEY_KP5: "KEY_KP5", + KEY_KP6: "KEY_KP6", + KEY_KPPLUS: "KEY_KPPLUS", + KEY_KP1: "KEY_KP1", + KEY_KP2: "KEY_KP2", + KEY_KP3: "KEY_KP3", + KEY_KP0: "KEY_KP0", + KEY_KPDOT: "KEY_KPDOT", + + KEY_ZENKAKUHANKAKU: "KEY_ZENKAKUHANKAKU", + KEY_102ND: "KEY_102ND", + KEY_F11: "KEY_F11", + KEY_F12: "KEY_F12", + KEY_RO: "KEY_RO", + KEY_KATAKANA: "KEY_KATAKANA", + KEY_HIRAGANA: "KEY_HIRAGANA", + KEY_HENKAN: "KEY_HENKAN", + KEY_KATAKANAHIRAGANA: "KEY_KATAKANAHIRAGANA", + KEY_MUHENKAN: "KEY_MUHENKAN", + KEY_KPJPCOMMA: "KEY_KPJPCOMMA", + KEY_KPENTER: "KEY_KPENTER", + KEY_RIGHTCTRL: "KEY_RIGHTCTRL", + KEY_KPSLASH: "KEY_KPSLASH", + KEY_SYSRQ: "KEY_SYSRQ", + KEY_RIGHTALT: "KEY_RIGHTALT", + KEY_LINEFEED: "KEY_LINEFEED", + KEY_HOME: "KEY_HOME", + KEY_UP: "KEY_UP", + KEY_PAGEUP: "KEY_PAGEUP", + KEY_LEFT: "KEY_LEFT", + KEY_RIGHT: "KEY_RIGHT", + KEY_END: "KEY_END", + KEY_DOWN: "KEY_DOWN", + KEY_PAGEDOWN: "KEY_PAGEDOWN", + KEY_INSERT: "KEY_INSERT", + KEY_DELETE: "KEY_DELETE", + KEY_MACRO: "KEY_MACRO", + KEY_MUTE: "KEY_MUTE/KEY_MIN_INTERESTING", + KEY_VOLUMEDOWN: "KEY_VOLUMEDOWN", + KEY_VOLUMEUP: "KEY_VOLUMEUP", + KEY_POWER: "KEY_POWER", + KEY_KPEQUAL: "KEY_KPEQUAL", + KEY_KPPLUSMINUS: "KEY_KPPLUSMINUS", + KEY_PAUSE: "KEY_PAUSE", + KEY_SCALE: "KEY_SCALE", + + KEY_KPCOMMA: "KEY_KPCOMMA", + KEY_HANGEUL: "KEY_HANGEUL/KEY_HANGUEL", + KEY_HANJA: "KEY_HANJA", + KEY_YEN: "KEY_YEN", + KEY_LEFTMETA: "KEY_LEFTMETA", + KEY_RIGHTMETA: "KEY_RIGHTMETA", + KEY_COMPOSE: "KEY_COMPOSE", + + KEY_STOP: "KEY_STOP", + KEY_AGAIN: "KEY_AGAIN", + KEY_PROPS: "KEY_PROPS", + KEY_UNDO: "KEY_UNDO", + KEY_FRONT: "KEY_FRONT", + KEY_COPY: "KEY_COPY", + KEY_OPEN: "KEY_OPEN", + KEY_PASTE: "KEY_PASTE", + KEY_FIND: "KEY_FIND", + KEY_CUT: "KEY_CUT", + KEY_HELP: "KEY_HELP", + KEY_MENU: "KEY_MENU", + KEY_CALC: "KEY_CALC", + KEY_SETUP: "KEY_SETUP", + KEY_SLEEP: "KEY_SLEEP", + KEY_WAKEUP: "KEY_WAKEUP", + KEY_FILE: "KEY_FILE", + KEY_SENDFILE: "KEY_SENDFILE", + KEY_DELETEFILE: "KEY_DELETEFILE", + KEY_XFER: "KEY_XFER", + KEY_PROG1: "KEY_PROG1", + KEY_PROG2: "KEY_PROG2", + KEY_WWW: "KEY_WWW", + KEY_MSDOS: "KEY_MSDOS", + KEY_COFFEE: "KEY_COFFEE/KEY_SCREENLOCK", + KEY_ROTATE_DISPLAY: "KEY_ROTATE_DISPLAY/KEY_DIRECTION", + KEY_CYCLEWINDOWS: "KEY_CYCLEWINDOWS", + KEY_MAIL: "KEY_MAIL", + KEY_BOOKMARKS: "KEY_BOOKMARKS", + KEY_COMPUTER: "KEY_COMPUTER", + KEY_BACK: "KEY_BACK", + KEY_FORWARD: "KEY_FORWARD", + KEY_CLOSECD: "KEY_CLOSECD", + KEY_EJECTCD: "KEY_EJECTCD", + KEY_EJECTCLOSECD: "KEY_EJECTCLOSECD", + KEY_NEXTSONG: "KEY_NEXTSONG", + KEY_PLAYPAUSE: "KEY_PLAYPAUSE", + KEY_PREVIOUSSONG: "KEY_PREVIOUSSONG", + KEY_STOPCD: "KEY_STOPCD", + KEY_RECORD: "KEY_RECORD", + KEY_REWIND: "KEY_REWIND", + KEY_PHONE: "KEY_PHONE", + KEY_ISO: "KEY_ISO", + KEY_CONFIG: "KEY_CONFIG", + KEY_HOMEPAGE: "KEY_HOMEPAGE", + KEY_REFRESH: "KEY_REFRESH", + KEY_EXIT: "KEY_EXIT", + KEY_MOVE: "KEY_MOVE", + KEY_EDIT: "KEY_EDIT", + KEY_SCROLLUP: "KEY_SCROLLUP", + KEY_SCROLLDOWN: "KEY_SCROLLDOWN", + KEY_KPLEFTPAREN: "KEY_KPLEFTPAREN", + KEY_KPRIGHTPAREN: "KEY_KPRIGHTPAREN", + KEY_NEW: "KEY_NEW", + KEY_REDO: "KEY_REDO", + + KEY_F13: "KEY_F13", + KEY_F14: "KEY_F14", + KEY_F15: "KEY_F15", + KEY_F16: "KEY_F16", + KEY_F17: "KEY_F17", + KEY_F18: "KEY_F18", + KEY_F19: "KEY_F19", + KEY_F20: "KEY_F20", + KEY_F21: "KEY_F21", + KEY_F22: "KEY_F22", + KEY_F23: "KEY_F23", + KEY_F24: "KEY_F24", + + KEY_PLAYCD: "KEY_PLAYCD", + KEY_PAUSECD: "KEY_PAUSECD", + KEY_PROG3: "KEY_PROG3", + KEY_PROG4: "KEY_PROG4", + KEY_ALL_APPLICATIONS: "KEY_ALL_APPLICATIONS/KEY_DASHBOARD", + KEY_SUSPEND: "KEY_SUSPEND", + KEY_CLOSE: "KEY_CLOSE", + KEY_PLAY: "KEY_PLAY", + KEY_FASTFORWARD: "KEY_FASTFORWARD", + KEY_BASSBOOST: "KEY_BASSBOOST", + KEY_PRINT: "KEY_PRINT", + KEY_HP: "KEY_HP", + KEY_CAMERA: "KEY_CAMERA", + KEY_SOUND: "KEY_SOUND", + KEY_QUESTION: "KEY_QUESTION", + KEY_EMAIL: "KEY_EMAIL", + KEY_CHAT: "KEY_CHAT", + KEY_SEARCH: "KEY_SEARCH", + KEY_CONNECT: "KEY_CONNECT", + KEY_FINANCE: "KEY_FINANCE", + KEY_SPORT: "KEY_SPORT", + KEY_SHOP: "KEY_SHOP", + KEY_ALTERASE: "KEY_ALTERASE", + KEY_CANCEL: "KEY_CANCEL", + KEY_BRIGHTNESSDOWN: "KEY_BRIGHTNESSDOWN", + KEY_BRIGHTNESSUP: "KEY_BRIGHTNESSUP", + KEY_MEDIA: "KEY_MEDIA", + + KEY_SWITCHVIDEOMODE: "KEY_SWITCHVIDEOMODE", + KEY_KBDILLUMTOGGLE: "KEY_KBDILLUMTOGGLE", + KEY_KBDILLUMDOWN: "KEY_KBDILLUMDOWN", + KEY_KBDILLUMUP: "KEY_KBDILLUMUP", + + KEY_SEND: "KEY_SEND", + KEY_REPLY: "KEY_REPLY", + KEY_FORWARDMAIL: "KEY_FORWARDMAIL", + KEY_SAVE: "KEY_SAVE", + KEY_DOCUMENTS: "KEY_DOCUMENTS", + + KEY_BATTERY: "KEY_BATTERY", + + KEY_BLUETOOTH: "KEY_BLUETOOTH", + KEY_WLAN: "KEY_WLAN", + KEY_UWB: "KEY_UWB", + + KEY_UNKNOWN: "KEY_UNKNOWN", + + KEY_VIDEO_NEXT: "KEY_VIDEO_NEXT", + KEY_VIDEO_PREV: "KEY_VIDEO_PREV", + KEY_BRIGHTNESS_CYCLE: "KEY_BRIGHTNESS_CYCLE", + KEY_BRIGHTNESS_AUTO: "KEY_BRIGHTNESS_AUTO/KEY_BRIGHTNESS_ZERO", + KEY_DISPLAY_OFF: "KEY_DISPLAY_OFF", + + KEY_WWAN: "KEY_WWAN/KEY_WIMAX", + KEY_RFKILL: "KEY_RFKILL", + + KEY_MICMUTE: "KEY_MICMUTE", + + BTN_MISC: "BTN_MISC/BTN_0", + BTN_1: "BTN_1", + BTN_2: "BTN_2", + BTN_3: "BTN_3", + BTN_4: "BTN_4", + BTN_5: "BTN_5", + BTN_6: "BTN_6", + BTN_7: "BTN_7", + BTN_8: "BTN_8", + BTN_9: "BTN_9", + + BTN_MOUSE: "BTN_MOUSE/BTN_LEFT", + BTN_RIGHT: "BTN_RIGHT", + BTN_MIDDLE: "BTN_MIDDLE", + BTN_SIDE: "BTN_SIDE", + BTN_EXTRA: "BTN_EXTRA", + BTN_FORWARD: "BTN_FORWARD", + BTN_BACK: "BTN_BACK", + BTN_TASK: "BTN_TASK", + + BTN_JOYSTICK: "BTN_JOYSTICK/BTN_TRIGGER", + BTN_THUMB: "BTN_THUMB", + BTN_THUMB2: "BTN_THUMB2", + BTN_TOP: "BTN_TOP", + BTN_TOP2: "BTN_TOP2", + BTN_PINKIE: "BTN_PINKIE", + BTN_BASE: "BTN_BASE", + BTN_BASE2: "BTN_BASE2", + BTN_BASE3: "BTN_BASE3", + BTN_BASE4: "BTN_BASE4", + BTN_BASE5: "BTN_BASE5", + BTN_BASE6: "BTN_BASE6", + BTN_DEAD: "BTN_DEAD", + + BTN_GAMEPAD: "BTN_GAMEPAD/BTN_SOUTH/BTN_A", + BTN_EAST: "BTN_EAST/BTN_B", + BTN_C: "BTN_C", + BTN_NORTH: "BTN_NORTH/BTN_X", + BTN_WEST: "BTN_WEST/BTN_Y", + BTN_Z: "BTN_Z", + BTN_TL: "BTN_TL", + BTN_TR: "BTN_TR", + BTN_TL2: "BTN_TL2", + BTN_TR2: "BTN_TR2", + BTN_SELECT: "BTN_SELECT", + BTN_START: "BTN_START", + BTN_MODE: "BTN_MODE", + BTN_THUMBL: "BTN_THUMBL", + BTN_THUMBR: "BTN_THUMBR", + + BTN_DIGI: "BTN_DIGI/BTN_TOOL_PEN", + BTN_TOOL_RUBBER: "BTN_TOOL_RUBBER", + BTN_TOOL_BRUSH: "BTN_TOOL_BRUSH", + BTN_TOOL_PENCIL: "BTN_TOOL_PENCIL", + BTN_TOOL_AIRBRUSH: "BTN_TOOL_AIRBRUSH", + BTN_TOOL_FINGER: "BTN_TOOL_FINGER", + BTN_TOOL_MOUSE: "BTN_TOOL_MOUSE", + BTN_TOOL_LENS: "BTN_TOOL_LENS", + BTN_TOOL_QUINTTAP: "BTN_TOOL_QUINTTAP", + BTN_STYLUS3: "BTN_STYLUS3", + BTN_TOUCH: "BTN_TOUCH", + BTN_STYLUS: "BTN_STYLUS", + BTN_STYLUS2: "BTN_STYLUS2", + BTN_TOOL_DOUBLETAP: "BTN_TOOL_DOUBLETAP", + BTN_TOOL_TRIPLETAP: "BTN_TOOL_TRIPLETAP", + BTN_TOOL_QUADTAP: "BTN_TOOL_QUADTAP", + + BTN_WHEEL: "BTN_WHEEL/BTN_GEAR_DOWN", + BTN_GEAR_UP: "BTN_GEAR_UP", + + KEY_OK: "KEY_OK", + KEY_SELECT: "KEY_SELECT", + KEY_GOTO: "KEY_GOTO", + KEY_CLEAR: "KEY_CLEAR", + KEY_POWER2: "KEY_POWER2", + KEY_OPTION: "KEY_OPTION", + KEY_INFO: "KEY_INFO", + KEY_TIME: "KEY_TIME", + KEY_VENDOR: "KEY_VENDOR", + KEY_ARCHIVE: "KEY_ARCHIVE", + KEY_PROGRAM: "KEY_PROGRAM", + KEY_CHANNEL: "KEY_CHANNEL", + KEY_FAVORITES: "KEY_FAVORITES", + KEY_EPG: "KEY_EPG", + KEY_PVR: "KEY_PVR", + KEY_MHP: "KEY_MHP", + KEY_LANGUAGE: "KEY_LANGUAGE", + KEY_TITLE: "KEY_TITLE", + KEY_SUBTITLE: "KEY_SUBTITLE", + KEY_ANGLE: "KEY_ANGLE", + KEY_FULL_SCREEN: "KEY_FULL_SCREEN/KEY_ZOOM", + KEY_MODE: "KEY_MODE", + KEY_KEYBOARD: "KEY_KEYBOARD", + KEY_ASPECT_RATIO: "KEY_ASPECT_RATIO/KEY_SCREEN", + KEY_PC: "KEY_PC", + KEY_TV: "KEY_TV", + KEY_TV2: "KEY_TV2", + KEY_VCR: "KEY_VCR", + KEY_VCR2: "KEY_VCR2", + KEY_SAT: "KEY_SAT", + KEY_SAT2: "KEY_SAT2", + KEY_CD: "KEY_CD", + KEY_TAPE: "KEY_TAPE", + KEY_RADIO: "KEY_RADIO", + KEY_TUNER: "KEY_TUNER", + KEY_PLAYER: "KEY_PLAYER", + KEY_TEXT: "KEY_TEXT", + KEY_DVD: "KEY_DVD", + KEY_AUX: "KEY_AUX", + KEY_MP3: "KEY_MP3", + KEY_AUDIO: "KEY_AUDIO", + KEY_VIDEO: "KEY_VIDEO", + KEY_DIRECTORY: "KEY_DIRECTORY", + KEY_LIST: "KEY_LIST", + KEY_MEMO: "KEY_MEMO", + KEY_CALENDAR: "KEY_CALENDAR", + KEY_RED: "KEY_RED", + KEY_GREEN: "KEY_GREEN", + KEY_YELLOW: "KEY_YELLOW", + KEY_BLUE: "KEY_BLUE", + KEY_CHANNELUP: "KEY_CHANNELUP", + KEY_CHANNELDOWN: "KEY_CHANNELDOWN", + KEY_FIRST: "KEY_FIRST", + KEY_LAST: "KEY_LAST", + KEY_AB: "KEY_AB", + KEY_NEXT: "KEY_NEXT", + KEY_RESTART: "KEY_RESTART", + KEY_SLOW: "KEY_SLOW", + KEY_SHUFFLE: "KEY_SHUFFLE", + KEY_BREAK: "KEY_BREAK", + KEY_PREVIOUS: "KEY_PREVIOUS", + KEY_DIGITS: "KEY_DIGITS", + KEY_TEEN: "KEY_TEEN", + KEY_TWEN: "KEY_TWEN", + KEY_VIDEOPHONE: "KEY_VIDEOPHONE", + KEY_GAMES: "KEY_GAMES", + KEY_ZOOMIN: "KEY_ZOOMIN", + KEY_ZOOMOUT: "KEY_ZOOMOUT", + KEY_ZOOMRESET: "KEY_ZOOMRESET", + KEY_WORDPROCESSOR: "KEY_WORDPROCESSOR", + KEY_EDITOR: "KEY_EDITOR", + KEY_SPREADSHEET: "KEY_SPREADSHEET", + KEY_GRAPHICSEDITOR: "KEY_GRAPHICSEDITOR", + KEY_PRESENTATION: "KEY_PRESENTATION", + KEY_DATABASE: "KEY_DATABASE", + KEY_NEWS: "KEY_NEWS", + KEY_VOICEMAIL: "KEY_VOICEMAIL", + KEY_ADDRESSBOOK: "KEY_ADDRESSBOOK", + KEY_MESSENGER: "KEY_MESSENGER", + KEY_DISPLAYTOGGLE: "KEY_DISPLAYTOGGLE/KEY_BRIGHTNESS_TOGGLE", + KEY_SPELLCHECK: "KEY_SPELLCHECK", + KEY_LOGOFF: "KEY_LOGOFF", + + KEY_DOLLAR: "KEY_DOLLAR", + KEY_EURO: "KEY_EURO", + + KEY_FRAMEBACK: "KEY_FRAMEBACK", + KEY_FRAMEFORWARD: "KEY_FRAMEFORWARD", + KEY_CONTEXT_MENU: "KEY_CONTEXT_MENU", + KEY_MEDIA_REPEAT: "KEY_MEDIA_REPEAT", + KEY_10CHANNELSUP: "KEY_10CHANNELSUP", + KEY_10CHANNELSDOWN: "KEY_10CHANNELSDOWN", + KEY_IMAGES: "KEY_IMAGES", + KEY_NOTIFICATION_CENTER: "KEY_NOTIFICATION_CENTER", + KEY_PICKUP_PHONE: "KEY_PICKUP_PHONE", + KEY_HANGUP_PHONE: "KEY_HANGUP_PHONE", + + KEY_DEL_EOL: "KEY_DEL_EOL", + KEY_DEL_EOS: "KEY_DEL_EOS", + KEY_INS_LINE: "KEY_INS_LINE", + KEY_DEL_LINE: "KEY_DEL_LINE", + + KEY_FN: "KEY_FN", + KEY_FN_ESC: "KEY_FN_ESC", + KEY_FN_F1: "KEY_FN_F1", + KEY_FN_F2: "KEY_FN_F2", + KEY_FN_F3: "KEY_FN_F3", + KEY_FN_F4: "KEY_FN_F4", + KEY_FN_F5: "KEY_FN_F5", + KEY_FN_F6: "KEY_FN_F6", + KEY_FN_F7: "KEY_FN_F7", + KEY_FN_F8: "KEY_FN_F8", + KEY_FN_F9: "KEY_FN_F9", + KEY_FN_F10: "KEY_FN_F10", + KEY_FN_F11: "KEY_FN_F11", + KEY_FN_F12: "KEY_FN_F12", + KEY_FN_1: "KEY_FN_1", + KEY_FN_2: "KEY_FN_2", + KEY_FN_D: "KEY_FN_D", + KEY_FN_E: "KEY_FN_E", + KEY_FN_F: "KEY_FN_F", + KEY_FN_S: "KEY_FN_S", + KEY_FN_B: "KEY_FN_B", + KEY_FN_RIGHT_SHIFT: "KEY_FN_RIGHT_SHIFT", + + KEY_BRL_DOT1: "KEY_BRL_DOT1", + KEY_BRL_DOT2: "KEY_BRL_DOT2", + KEY_BRL_DOT3: "KEY_BRL_DOT3", + KEY_BRL_DOT4: "KEY_BRL_DOT4", + KEY_BRL_DOT5: "KEY_BRL_DOT5", + KEY_BRL_DOT6: "KEY_BRL_DOT6", + KEY_BRL_DOT7: "KEY_BRL_DOT7", + KEY_BRL_DOT8: "KEY_BRL_DOT8", + KEY_BRL_DOT9: "KEY_BRL_DOT9", + KEY_BRL_DOT10: "KEY_BRL_DOT10", + + KEY_NUMERIC_0: "KEY_NUMERIC_0", + KEY_NUMERIC_1: "KEY_NUMERIC_1", + KEY_NUMERIC_2: "KEY_NUMERIC_2", + KEY_NUMERIC_3: "KEY_NUMERIC_3", + KEY_NUMERIC_4: "KEY_NUMERIC_4", + KEY_NUMERIC_5: "KEY_NUMERIC_5", + KEY_NUMERIC_6: "KEY_NUMERIC_6", + KEY_NUMERIC_7: "KEY_NUMERIC_7", + KEY_NUMERIC_8: "KEY_NUMERIC_8", + KEY_NUMERIC_9: "KEY_NUMERIC_9", + KEY_NUMERIC_STAR: "KEY_NUMERIC_STAR", + KEY_NUMERIC_POUND: "KEY_NUMERIC_POUND", + KEY_NUMERIC_A: "KEY_NUMERIC_A", + KEY_NUMERIC_B: "KEY_NUMERIC_B", + KEY_NUMERIC_C: "KEY_NUMERIC_C", + KEY_NUMERIC_D: "KEY_NUMERIC_D", + + KEY_CAMERA_FOCUS: "KEY_CAMERA_FOCUS", + KEY_WPS_BUTTON: "KEY_WPS_BUTTON", + + KEY_TOUCHPAD_TOGGLE: "KEY_TOUCHPAD_TOGGLE", + KEY_TOUCHPAD_ON: "KEY_TOUCHPAD_ON", + KEY_TOUCHPAD_OFF: "KEY_TOUCHPAD_OFF", + + KEY_CAMERA_ZOOMIN: "KEY_CAMERA_ZOOMIN", + KEY_CAMERA_ZOOMOUT: "KEY_CAMERA_ZOOMOUT", + KEY_CAMERA_UP: "KEY_CAMERA_UP", + KEY_CAMERA_DOWN: "KEY_CAMERA_DOWN", + KEY_CAMERA_LEFT: "KEY_CAMERA_LEFT", + KEY_CAMERA_RIGHT: "KEY_CAMERA_RIGHT", + + KEY_ATTENDANT_ON: "KEY_ATTENDANT_ON", + KEY_ATTENDANT_OFF: "KEY_ATTENDANT_OFF", + KEY_ATTENDANT_TOGGLE: "KEY_ATTENDANT_TOGGLE", + KEY_LIGHTS_TOGGLE: "KEY_LIGHTS_TOGGLE", + + BTN_DPAD_UP: "BTN_DPAD_UP", + BTN_DPAD_DOWN: "BTN_DPAD_DOWN", + BTN_DPAD_LEFT: "BTN_DPAD_LEFT", + BTN_DPAD_RIGHT: "BTN_DPAD_RIGHT", + + KEY_ALS_TOGGLE: "KEY_ALS_TOGGLE", + KEY_ROTATE_LOCK_TOGGLE: "KEY_ROTATE_LOCK_TOGGLE", + + KEY_BUTTONCONFIG: "KEY_BUTTONCONFIG", + KEY_TASKMANAGER: "KEY_TASKMANAGER", + KEY_JOURNAL: "KEY_JOURNAL", + KEY_CONTROLPANEL: "KEY_CONTROLPANEL", + KEY_APPSELECT: "KEY_APPSELECT", + KEY_SCREENSAVER: "KEY_SCREENSAVER", + KEY_VOICECOMMAND: "KEY_VOICECOMMAND", + KEY_ASSISTANT: "KEY_ASSISTANT", + KEY_KBD_LAYOUT_NEXT: "KEY_KBD_LAYOUT_NEXT", + KEY_EMOJI_PICKER: "KEY_EMOJI_PICKER", + KEY_DICTATE: "KEY_DICTATE", + + KEY_BRIGHTNESS_MIN: "KEY_BRIGHTNESS_MIN", + KEY_BRIGHTNESS_MAX: "KEY_BRIGHTNESS_MAX", + + KEY_KBDINPUTASSIST_PREV: "KEY_KBDINPUTASSIST_PREV", + KEY_KBDINPUTASSIST_NEXT: "KEY_KBDINPUTASSIST_NEXT", + KEY_KBDINPUTASSIST_PREVGROUP: "KEY_KBDINPUTASSIST_PREVGROUP", + KEY_KBDINPUTASSIST_NEXTGROUP: "KEY_KBDINPUTASSIST_NEXTGROUP", + KEY_KBDINPUTASSIST_ACCEPT: "KEY_KBDINPUTASSIST_ACCEPT", + KEY_KBDINPUTASSIST_CANCEL: "KEY_KBDINPUTASSIST_CANCEL", + + KEY_RIGHT_UP: "KEY_RIGHT_UP", + KEY_RIGHT_DOWN: "KEY_RIGHT_DOWN", + KEY_LEFT_UP: "KEY_LEFT_UP", + KEY_LEFT_DOWN: "KEY_LEFT_DOWN", + + KEY_ROOT_MENU: "KEY_ROOT_MENU", + + KEY_MEDIA_TOP_MENU: "KEY_MEDIA_TOP_MENU", + KEY_NUMERIC_11: "KEY_NUMERIC_11", + KEY_NUMERIC_12: "KEY_NUMERIC_12", + + KEY_AUDIO_DESC: "KEY_AUDIO_DESC", + KEY_3D_MODE: "KEY_3D_MODE", + KEY_NEXT_FAVORITE: "KEY_NEXT_FAVORITE", + KEY_STOP_RECORD: "KEY_STOP_RECORD", + KEY_PAUSE_RECORD: "KEY_PAUSE_RECORD", + KEY_VOD: "KEY_VOD", + KEY_UNMUTE: "KEY_UNMUTE", + KEY_FASTREVERSE: "KEY_FASTREVERSE", + KEY_SLOWREVERSE: "KEY_SLOWREVERSE", + + KEY_DATA: "KEY_DATA", + KEY_ONSCREEN_KEYBOARD: "KEY_ONSCREEN_KEYBOARD", + + KEY_PRIVACY_SCREEN_TOGGLE: "KEY_PRIVACY_SCREEN_TOGGLE", + + KEY_SELECTIVE_SCREENSHOT: "KEY_SELECTIVE_SCREENSHOT", + + KEY_MACRO1: "KEY_MACRO1", + KEY_MACRO2: "KEY_MACRO2", + KEY_MACRO3: "KEY_MACRO3", + KEY_MACRO4: "KEY_MACRO4", + KEY_MACRO5: "KEY_MACRO5", + KEY_MACRO6: "KEY_MACRO6", + KEY_MACRO7: "KEY_MACRO7", + KEY_MACRO8: "KEY_MACRO8", + KEY_MACRO9: "KEY_MACRO9", + KEY_MACRO10: "KEY_MACRO10", + KEY_MACRO11: "KEY_MACRO11", + KEY_MACRO12: "KEY_MACRO12", + KEY_MACRO13: "KEY_MACRO13", + KEY_MACRO14: "KEY_MACRO14", + KEY_MACRO15: "KEY_MACRO15", + KEY_MACRO16: "KEY_MACRO16", + KEY_MACRO17: "KEY_MACRO17", + KEY_MACRO18: "KEY_MACRO18", + KEY_MACRO19: "KEY_MACRO19", + KEY_MACRO20: "KEY_MACRO20", + KEY_MACRO21: "KEY_MACRO21", + KEY_MACRO22: "KEY_MACRO22", + KEY_MACRO23: "KEY_MACRO23", + KEY_MACRO24: "KEY_MACRO24", + KEY_MACRO25: "KEY_MACRO25", + KEY_MACRO26: "KEY_MACRO26", + KEY_MACRO27: "KEY_MACRO27", + KEY_MACRO28: "KEY_MACRO28", + KEY_MACRO29: "KEY_MACRO29", + KEY_MACRO30: "KEY_MACRO30", + + KEY_MACRO_RECORD_START: "KEY_MACRO_RECORD_START", + KEY_MACRO_RECORD_STOP: "KEY_MACRO_RECORD_STOP", + KEY_MACRO_PRESET_CYCLE: "KEY_MACRO_PRESET_CYCLE", + KEY_MACRO_PRESET1: "KEY_MACRO_PRESET1", + KEY_MACRO_PRESET2: "KEY_MACRO_PRESET2", + KEY_MACRO_PRESET3: "KEY_MACRO_PRESET3", + + KEY_KBD_LCD_MENU1: "KEY_KBD_LCD_MENU1", + KEY_KBD_LCD_MENU2: "KEY_KBD_LCD_MENU2", + KEY_KBD_LCD_MENU3: "KEY_KBD_LCD_MENU3", + KEY_KBD_LCD_MENU4: "KEY_KBD_LCD_MENU4", + KEY_KBD_LCD_MENU5: "KEY_KBD_LCD_MENU5", + + BTN_TRIGGER_HAPPY: "BTN_TRIGGER_HAPPY/BTN_TRIGGER_HAPPY1", + BTN_TRIGGER_HAPPY2: "BTN_TRIGGER_HAPPY2", + BTN_TRIGGER_HAPPY3: "BTN_TRIGGER_HAPPY3", + BTN_TRIGGER_HAPPY4: "BTN_TRIGGER_HAPPY4", + BTN_TRIGGER_HAPPY5: "BTN_TRIGGER_HAPPY5", + BTN_TRIGGER_HAPPY6: "BTN_TRIGGER_HAPPY6", + BTN_TRIGGER_HAPPY7: "BTN_TRIGGER_HAPPY7", + BTN_TRIGGER_HAPPY8: "BTN_TRIGGER_HAPPY8", + BTN_TRIGGER_HAPPY9: "BTN_TRIGGER_HAPPY9", + BTN_TRIGGER_HAPPY10: "BTN_TRIGGER_HAPPY10", + BTN_TRIGGER_HAPPY11: "BTN_TRIGGER_HAPPY11", + BTN_TRIGGER_HAPPY12: "BTN_TRIGGER_HAPPY12", + BTN_TRIGGER_HAPPY13: "BTN_TRIGGER_HAPPY13", + BTN_TRIGGER_HAPPY14: "BTN_TRIGGER_HAPPY14", + BTN_TRIGGER_HAPPY15: "BTN_TRIGGER_HAPPY15", + BTN_TRIGGER_HAPPY16: "BTN_TRIGGER_HAPPY16", + BTN_TRIGGER_HAPPY17: "BTN_TRIGGER_HAPPY17", + BTN_TRIGGER_HAPPY18: "BTN_TRIGGER_HAPPY18", + BTN_TRIGGER_HAPPY19: "BTN_TRIGGER_HAPPY19", + BTN_TRIGGER_HAPPY20: "BTN_TRIGGER_HAPPY20", + BTN_TRIGGER_HAPPY21: "BTN_TRIGGER_HAPPY21", + BTN_TRIGGER_HAPPY22: "BTN_TRIGGER_HAPPY22", + BTN_TRIGGER_HAPPY23: "BTN_TRIGGER_HAPPY23", + BTN_TRIGGER_HAPPY24: "BTN_TRIGGER_HAPPY24", + BTN_TRIGGER_HAPPY25: "BTN_TRIGGER_HAPPY25", + BTN_TRIGGER_HAPPY26: "BTN_TRIGGER_HAPPY26", + BTN_TRIGGER_HAPPY27: "BTN_TRIGGER_HAPPY27", + BTN_TRIGGER_HAPPY28: "BTN_TRIGGER_HAPPY28", + BTN_TRIGGER_HAPPY29: "BTN_TRIGGER_HAPPY29", + BTN_TRIGGER_HAPPY30: "BTN_TRIGGER_HAPPY30", + BTN_TRIGGER_HAPPY31: "BTN_TRIGGER_HAPPY31", + BTN_TRIGGER_HAPPY32: "BTN_TRIGGER_HAPPY32", + BTN_TRIGGER_HAPPY33: "BTN_TRIGGER_HAPPY33", + BTN_TRIGGER_HAPPY34: "BTN_TRIGGER_HAPPY34", + BTN_TRIGGER_HAPPY35: "BTN_TRIGGER_HAPPY35", + BTN_TRIGGER_HAPPY36: "BTN_TRIGGER_HAPPY36", + BTN_TRIGGER_HAPPY37: "BTN_TRIGGER_HAPPY37", + BTN_TRIGGER_HAPPY38: "BTN_TRIGGER_HAPPY38", + BTN_TRIGGER_HAPPY39: "BTN_TRIGGER_HAPPY39", + BTN_TRIGGER_HAPPY40: "BTN_TRIGGER_HAPPY40", + + KEY_MAX: "KEY_MAX", + KEY_CNT: "KEY_CNT", +} + +var RELNames = map[EvCode]string{ + REL_X: "REL_X", + REL_Y: "REL_Y", + REL_Z: "REL_Z", + REL_RX: "REL_RX", + REL_RY: "REL_RY", + REL_RZ: "REL_RZ", + REL_HWHEEL: "REL_HWHEEL", + REL_DIAL: "REL_DIAL", + REL_WHEEL: "REL_WHEEL", + REL_MISC: "REL_MISC", + + REL_RESERVED: "REL_RESERVED", + REL_WHEEL_HI_RES: "REL_WHEEL_HI_RES", + REL_HWHEEL_HI_RES: "REL_HWHEEL_HI_RES", + REL_MAX: "REL_MAX", + REL_CNT: "REL_CNT", +} + +var ABSNames = map[EvCode]string{ + ABS_X: "ABS_X", + ABS_Y: "ABS_Y", + ABS_Z: "ABS_Z", + ABS_RX: "ABS_RX", + ABS_RY: "ABS_RY", + ABS_RZ: "ABS_RZ", + ABS_THROTTLE: "ABS_THROTTLE", + ABS_RUDDER: "ABS_RUDDER", + ABS_WHEEL: "ABS_WHEEL", + ABS_GAS: "ABS_GAS", + ABS_BRAKE: "ABS_BRAKE", + ABS_HAT0X: "ABS_HAT0X", + ABS_HAT0Y: "ABS_HAT0Y", + ABS_HAT1X: "ABS_HAT1X", + ABS_HAT1Y: "ABS_HAT1Y", + ABS_HAT2X: "ABS_HAT2X", + ABS_HAT2Y: "ABS_HAT2Y", + ABS_HAT3X: "ABS_HAT3X", + ABS_HAT3Y: "ABS_HAT3Y", + ABS_PRESSURE: "ABS_PRESSURE", + ABS_DISTANCE: "ABS_DISTANCE", + ABS_TILT_X: "ABS_TILT_X", + ABS_TILT_Y: "ABS_TILT_Y", + ABS_TOOL_WIDTH: "ABS_TOOL_WIDTH", + + ABS_VOLUME: "ABS_VOLUME", + + ABS_MISC: "ABS_MISC", + + ABS_RESERVED: "ABS_RESERVED", + + ABS_MT_SLOT: "ABS_MT_SLOT", + ABS_MT_TOUCH_MAJOR: "ABS_MT_TOUCH_MAJOR", + ABS_MT_TOUCH_MINOR: "ABS_MT_TOUCH_MINOR", + ABS_MT_WIDTH_MAJOR: "ABS_MT_WIDTH_MAJOR", + ABS_MT_WIDTH_MINOR: "ABS_MT_WIDTH_MINOR", + ABS_MT_ORIENTATION: "ABS_MT_ORIENTATION", + ABS_MT_POSITION_X: "ABS_MT_POSITION_X", + ABS_MT_POSITION_Y: "ABS_MT_POSITION_Y", + ABS_MT_TOOL_TYPE: "ABS_MT_TOOL_TYPE", + ABS_MT_BLOB_ID: "ABS_MT_BLOB_ID", + ABS_MT_TRACKING_ID: "ABS_MT_TRACKING_ID", + ABS_MT_PRESSURE: "ABS_MT_PRESSURE", + ABS_MT_DISTANCE: "ABS_MT_DISTANCE", + ABS_MT_TOOL_X: "ABS_MT_TOOL_X", + ABS_MT_TOOL_Y: "ABS_MT_TOOL_Y", + + ABS_MAX: "ABS_MAX", + ABS_CNT: "ABS_CNT", +} + +var SWNames = map[EvCode]string{ + SW_LID: "SW_LID", + SW_TABLET_MODE: "SW_TABLET_MODE", + SW_HEADPHONE_INSERT: "SW_HEADPHONE_INSERT", + SW_RFKILL_ALL: "SW_RFKILL_ALL/SW_RADIO", + SW_MICROPHONE_INSERT: "SW_MICROPHONE_INSERT", + SW_DOCK: "SW_DOCK", + SW_LINEOUT_INSERT: "SW_LINEOUT_INSERT", + SW_JACK_PHYSICAL_INSERT: "SW_JACK_PHYSICAL_INSERT", + SW_VIDEOOUT_INSERT: "SW_VIDEOOUT_INSERT", + SW_CAMERA_LENS_COVER: "SW_CAMERA_LENS_COVER", + SW_KEYPAD_SLIDE: "SW_KEYPAD_SLIDE", + SW_FRONT_PROXIMITY: "SW_FRONT_PROXIMITY", + SW_ROTATE_LOCK: "SW_ROTATE_LOCK", + SW_LINEIN_INSERT: "SW_LINEIN_INSERT", + SW_MUTE_DEVICE: "SW_MUTE_DEVICE", + SW_PEN_INSERTED: "SW_PEN_INSERTED", + SW_MACHINE_COVER: "SW_MACHINE_COVER/SW_MAX", + SW_CNT: "SW_CNT", +} + +var MSCNames = map[EvCode]string{ + MSC_SERIAL: "MSC_SERIAL", + MSC_PULSELED: "MSC_PULSELED", + MSC_GESTURE: "MSC_GESTURE", + MSC_RAW: "MSC_RAW", + MSC_SCAN: "MSC_SCAN", + MSC_TIMESTAMP: "MSC_TIMESTAMP", + MSC_MAX: "MSC_MAX", + MSC_CNT: "MSC_CNT", +} + +var LEDNames = map[EvCode]string{ + LED_NUML: "LED_NUML", + LED_CAPSL: "LED_CAPSL", + LED_SCROLLL: "LED_SCROLLL", + LED_COMPOSE: "LED_COMPOSE", + LED_KANA: "LED_KANA", + LED_SLEEP: "LED_SLEEP", + LED_SUSPEND: "LED_SUSPEND", + LED_MUTE: "LED_MUTE", + LED_MISC: "LED_MISC", + LED_MAIL: "LED_MAIL", + LED_CHARGING: "LED_CHARGING", + LED_MAX: "LED_MAX", + LED_CNT: "LED_CNT", +} + +var REPNames = map[EvCode]string{ + REP_DELAY: "REP_DELAY", + REP_PERIOD: "REP_PERIOD/REP_MAX", + REP_CNT: "REP_CNT", +} + +var SNDNames = map[EvCode]string{ + SND_CLICK: "SND_CLICK", + SND_BELL: "SND_BELL", + SND_TONE: "SND_TONE", + SND_MAX: "SND_MAX", + SND_CNT: "SND_CNT", +} + +var IDNames = map[EvCode]string{ + ID_BUS: "ID_BUS", + ID_VENDOR: "ID_VENDOR", + ID_PRODUCT: "ID_PRODUCT", + ID_VERSION: "ID_VERSION", +} + +var BUSNames = map[EvCode]string{ + BUS_PCI: "BUS_PCI", + BUS_ISAPNP: "BUS_ISAPNP", + BUS_USB: "BUS_USB", + BUS_HIL: "BUS_HIL", + BUS_BLUETOOTH: "BUS_BLUETOOTH", + BUS_VIRTUAL: "BUS_VIRTUAL", + + BUS_ISA: "BUS_ISA", + BUS_I8042: "BUS_I8042", + BUS_XTKBD: "BUS_XTKBD", + BUS_RS232: "BUS_RS232", + BUS_GAMEPORT: "BUS_GAMEPORT", + BUS_PARPORT: "BUS_PARPORT", + BUS_AMIGA: "BUS_AMIGA", + BUS_ADB: "BUS_ADB", + BUS_I2C: "BUS_I2C", + BUS_HOST: "BUS_HOST", + BUS_GSC: "BUS_GSC", + BUS_ATARI: "BUS_ATARI", + BUS_SPI: "BUS_SPI", + BUS_RMI: "BUS_RMI", + BUS_CEC: "BUS_CEC", + BUS_INTEL_ISHTP: "BUS_INTEL_ISHTP", +} + +var MTNames = map[EvCode]string{ + MT_TOOL_FINGER: "MT_TOOL_FINGER", + MT_TOOL_PEN: "MT_TOOL_PEN", + MT_TOOL_PALM: "MT_TOOL_PALM", + MT_TOOL_DIAL: "MT_TOOL_DIAL", + MT_TOOL_MAX: "MT_TOOL_MAX", +} + +var FFNames = map[EvCode]string{ + FF_STATUS_STOPPED: "FF_STATUS_STOPPED", + FF_STATUS_PLAYING: "FF_STATUS_PLAYING/FF_STATUS_MAX", + + FF_RUMBLE: "FF_RUMBLE/FF_EFFECT_MIN", + FF_PERIODIC: "FF_PERIODIC", + FF_CONSTANT: "FF_CONSTANT", + FF_SPRING: "FF_SPRING", + FF_FRICTION: "FF_FRICTION", + FF_DAMPER: "FF_DAMPER", + FF_INERTIA: "FF_INERTIA", + FF_RAMP: "FF_RAMP/FF_EFFECT_MAX", + + FF_SQUARE: "FF_SQUARE/FF_WAVEFORM_MIN", + FF_TRIANGLE: "FF_TRIANGLE", + FF_SINE: "FF_SINE", + FF_SAW_UP: "FF_SAW_UP", + FF_SAW_DOWN: "FF_SAW_DOWN", + FF_CUSTOM: "FF_CUSTOM/FF_WAVEFORM_MAX", + + FF_GAIN: "FF_GAIN/FF_MAX_EFFECTS", + FF_AUTOCENTER: "FF_AUTOCENTER", + + FF_MAX: "FF_MAX", + FF_CNT: "FF_CNT", +} diff --git a/vendor/github.com/holoplot/go-evdev/device.go b/vendor/github.com/holoplot/go-evdev/device.go new file mode 100644 index 0000000..40e98e4 --- /dev/null +++ b/vendor/github.com/holoplot/go-evdev/device.go @@ -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) +} diff --git a/vendor/github.com/holoplot/go-evdev/ioctl.go b/vendor/github.com/holoplot/go-evdev/ioctl.go new file mode 100644 index 0000000..18b6a09 --- /dev/null +++ b/vendor/github.com/holoplot/go-evdev/ioctl.go @@ -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) +} diff --git a/vendor/github.com/holoplot/go-evdev/list.go b/vendor/github.com/holoplot/go-evdev/list.go new file mode 100644 index 0000000..51a8107 --- /dev/null +++ b/vendor/github.com/holoplot/go-evdev/list.go @@ -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 +} diff --git a/vendor/github.com/holoplot/go-evdev/names.go b/vendor/github.com/holoplot/go-evdev/names.go new file mode 100644 index 0000000..c7a0a24 --- /dev/null +++ b/vendor/github.com/holoplot/go-evdev/names.go @@ -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 +} diff --git a/vendor/github.com/holoplot/go-evdev/types.go b/vendor/github.com/holoplot/go-evdev/types.go new file mode 100644 index 0000000..c227cc2 --- /dev/null +++ b/vendor/github.com/holoplot/go-evdev/types.go @@ -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 +} diff --git a/vendor/github.com/holoplot/go-evdev/uinput.go b/vendor/github.com/holoplot/go-evdev/uinput.go new file mode 100644 index 0000000..0f2a691 --- /dev/null +++ b/vendor/github.com/holoplot/go-evdev/uinput.go @@ -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 +} diff --git a/vendor/github.com/szatmary/sonos/.gitignore b/vendor/github.com/szatmary/sonos/.gitignore new file mode 100644 index 0000000..f1c181e --- /dev/null +++ b/vendor/github.com/szatmary/sonos/.gitignore @@ -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 diff --git a/vendor/github.com/szatmary/sonos/AVTransport/AVTransport.go b/vendor/github.com/szatmary/sonos/AVTransport/AVTransport.go new file mode 100644 index 0000000..3e69390 --- /dev/null +++ b/vendor/github.com/szatmary/sonos/AVTransport/AVTransport.go @@ -0,0 +1,1379 @@ +package avtransport + +import ( + "bytes" + "encoding/xml" + "errors" + "io/ioutil" + "net/http" + "net/url" +) + +const ( + _ServiceURN = "urn:schemas-upnp-org:service:AVTransport: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/AVTransport/Control`) + if nil != err { + panic(err) + } + e, err := url.Parse(`/MediaRenderer/AVTransport/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"` + SetAVTransportURI *SetAVTransportURIArgs `xml:"u:SetAVTransportURI,omitempty"` + SetNextAVTransportURI *SetNextAVTransportURIArgs `xml:"u:SetNextAVTransportURI,omitempty"` + AddURIToQueue *AddURIToQueueArgs `xml:"u:AddURIToQueue,omitempty"` + AddMultipleURIsToQueue *AddMultipleURIsToQueueArgs `xml:"u:AddMultipleURIsToQueue,omitempty"` + ReorderTracksInQueue *ReorderTracksInQueueArgs `xml:"u:ReorderTracksInQueue,omitempty"` + RemoveTrackFromQueue *RemoveTrackFromQueueArgs `xml:"u:RemoveTrackFromQueue,omitempty"` + RemoveTrackRangeFromQueue *RemoveTrackRangeFromQueueArgs `xml:"u:RemoveTrackRangeFromQueue,omitempty"` + RemoveAllTracksFromQueue *RemoveAllTracksFromQueueArgs `xml:"u:RemoveAllTracksFromQueue,omitempty"` + SaveQueue *SaveQueueArgs `xml:"u:SaveQueue,omitempty"` + BackupQueue *BackupQueueArgs `xml:"u:BackupQueue,omitempty"` + CreateSavedQueue *CreateSavedQueueArgs `xml:"u:CreateSavedQueue,omitempty"` + AddURIToSavedQueue *AddURIToSavedQueueArgs `xml:"u:AddURIToSavedQueue,omitempty"` + ReorderTracksInSavedQueue *ReorderTracksInSavedQueueArgs `xml:"u:ReorderTracksInSavedQueue,omitempty"` + GetMediaInfo *GetMediaInfoArgs `xml:"u:GetMediaInfo,omitempty"` + GetTransportInfo *GetTransportInfoArgs `xml:"u:GetTransportInfo,omitempty"` + GetPositionInfo *GetPositionInfoArgs `xml:"u:GetPositionInfo,omitempty"` + GetDeviceCapabilities *GetDeviceCapabilitiesArgs `xml:"u:GetDeviceCapabilities,omitempty"` + GetTransportSettings *GetTransportSettingsArgs `xml:"u:GetTransportSettings,omitempty"` + GetCrossfadeMode *GetCrossfadeModeArgs `xml:"u:GetCrossfadeMode,omitempty"` + Stop *StopArgs `xml:"u:Stop,omitempty"` + Play *PlayArgs `xml:"u:Play,omitempty"` + Pause *PauseArgs `xml:"u:Pause,omitempty"` + Seek *SeekArgs `xml:"u:Seek,omitempty"` + Next *NextArgs `xml:"u:Next,omitempty"` + Previous *PreviousArgs `xml:"u:Previous,omitempty"` + SetPlayMode *SetPlayModeArgs `xml:"u:SetPlayMode,omitempty"` + SetCrossfadeMode *SetCrossfadeModeArgs `xml:"u:SetCrossfadeMode,omitempty"` + NotifyDeletedURI *NotifyDeletedURIArgs `xml:"u:NotifyDeletedURI,omitempty"` + GetCurrentTransportActions *GetCurrentTransportActionsArgs `xml:"u:GetCurrentTransportActions,omitempty"` + BecomeCoordinatorOfStandaloneGroup *BecomeCoordinatorOfStandaloneGroupArgs `xml:"u:BecomeCoordinatorOfStandaloneGroup,omitempty"` + DelegateGroupCoordinationTo *DelegateGroupCoordinationToArgs `xml:"u:DelegateGroupCoordinationTo,omitempty"` + BecomeGroupCoordinator *BecomeGroupCoordinatorArgs `xml:"u:BecomeGroupCoordinator,omitempty"` + BecomeGroupCoordinatorAndSource *BecomeGroupCoordinatorAndSourceArgs `xml:"u:BecomeGroupCoordinatorAndSource,omitempty"` + ChangeCoordinator *ChangeCoordinatorArgs `xml:"u:ChangeCoordinator,omitempty"` + ChangeTransportSettings *ChangeTransportSettingsArgs `xml:"u:ChangeTransportSettings,omitempty"` + ConfigureSleepTimer *ConfigureSleepTimerArgs `xml:"u:ConfigureSleepTimer,omitempty"` + GetRemainingSleepTimerDuration *GetRemainingSleepTimerDurationArgs `xml:"u:GetRemainingSleepTimerDuration,omitempty"` + RunAlarm *RunAlarmArgs `xml:"u:RunAlarm,omitempty"` + StartAutoplay *StartAutoplayArgs `xml:"u:StartAutoplay,omitempty"` + GetRunningAlarmProperties *GetRunningAlarmPropertiesArgs `xml:"u:GetRunningAlarmProperties,omitempty"` + SnoozeAlarm *SnoozeAlarmArgs `xml:"u:SnoozeAlarm,omitempty"` + EndDirectControlSession *EndDirectControlSessionArgs `xml:"u:EndDirectControlSession,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"` + SetAVTransportURI *SetAVTransportURIResponse `xml:"SetAVTransportURIResponse,omitempty"` + SetNextAVTransportURI *SetNextAVTransportURIResponse `xml:"SetNextAVTransportURIResponse,omitempty"` + AddURIToQueue *AddURIToQueueResponse `xml:"AddURIToQueueResponse,omitempty"` + AddMultipleURIsToQueue *AddMultipleURIsToQueueResponse `xml:"AddMultipleURIsToQueueResponse,omitempty"` + ReorderTracksInQueue *ReorderTracksInQueueResponse `xml:"ReorderTracksInQueueResponse,omitempty"` + RemoveTrackFromQueue *RemoveTrackFromQueueResponse `xml:"RemoveTrackFromQueueResponse,omitempty"` + RemoveTrackRangeFromQueue *RemoveTrackRangeFromQueueResponse `xml:"RemoveTrackRangeFromQueueResponse,omitempty"` + RemoveAllTracksFromQueue *RemoveAllTracksFromQueueResponse `xml:"RemoveAllTracksFromQueueResponse,omitempty"` + SaveQueue *SaveQueueResponse `xml:"SaveQueueResponse,omitempty"` + BackupQueue *BackupQueueResponse `xml:"BackupQueueResponse,omitempty"` + CreateSavedQueue *CreateSavedQueueResponse `xml:"CreateSavedQueueResponse,omitempty"` + AddURIToSavedQueue *AddURIToSavedQueueResponse `xml:"AddURIToSavedQueueResponse,omitempty"` + ReorderTracksInSavedQueue *ReorderTracksInSavedQueueResponse `xml:"ReorderTracksInSavedQueueResponse,omitempty"` + GetMediaInfo *GetMediaInfoResponse `xml:"GetMediaInfoResponse,omitempty"` + GetTransportInfo *GetTransportInfoResponse `xml:"GetTransportInfoResponse,omitempty"` + GetPositionInfo *GetPositionInfoResponse `xml:"GetPositionInfoResponse,omitempty"` + GetDeviceCapabilities *GetDeviceCapabilitiesResponse `xml:"GetDeviceCapabilitiesResponse,omitempty"` + GetTransportSettings *GetTransportSettingsResponse `xml:"GetTransportSettingsResponse,omitempty"` + GetCrossfadeMode *GetCrossfadeModeResponse `xml:"GetCrossfadeModeResponse,omitempty"` + Stop *StopResponse `xml:"StopResponse,omitempty"` + Play *PlayResponse `xml:"PlayResponse,omitempty"` + Pause *PauseResponse `xml:"PauseResponse,omitempty"` + Seek *SeekResponse `xml:"SeekResponse,omitempty"` + Next *NextResponse `xml:"NextResponse,omitempty"` + Previous *PreviousResponse `xml:"PreviousResponse,omitempty"` + SetPlayMode *SetPlayModeResponse `xml:"SetPlayModeResponse,omitempty"` + SetCrossfadeMode *SetCrossfadeModeResponse `xml:"SetCrossfadeModeResponse,omitempty"` + NotifyDeletedURI *NotifyDeletedURIResponse `xml:"NotifyDeletedURIResponse,omitempty"` + GetCurrentTransportActions *GetCurrentTransportActionsResponse `xml:"GetCurrentTransportActionsResponse,omitempty"` + BecomeCoordinatorOfStandaloneGroup *BecomeCoordinatorOfStandaloneGroupResponse `xml:"BecomeCoordinatorOfStandaloneGroupResponse,omitempty"` + DelegateGroupCoordinationTo *DelegateGroupCoordinationToResponse `xml:"DelegateGroupCoordinationToResponse,omitempty"` + BecomeGroupCoordinator *BecomeGroupCoordinatorResponse `xml:"BecomeGroupCoordinatorResponse,omitempty"` + BecomeGroupCoordinatorAndSource *BecomeGroupCoordinatorAndSourceResponse `xml:"BecomeGroupCoordinatorAndSourceResponse,omitempty"` + ChangeCoordinator *ChangeCoordinatorResponse `xml:"ChangeCoordinatorResponse,omitempty"` + ChangeTransportSettings *ChangeTransportSettingsResponse `xml:"ChangeTransportSettingsResponse,omitempty"` + ConfigureSleepTimer *ConfigureSleepTimerResponse `xml:"ConfigureSleepTimerResponse,omitempty"` + GetRemainingSleepTimerDuration *GetRemainingSleepTimerDurationResponse `xml:"GetRemainingSleepTimerDurationResponse,omitempty"` + RunAlarm *RunAlarmResponse `xml:"RunAlarmResponse,omitempty"` + StartAutoplay *StartAutoplayResponse `xml:"StartAutoplayResponse,omitempty"` + GetRunningAlarmProperties *GetRunningAlarmPropertiesResponse `xml:"GetRunningAlarmPropertiesResponse,omitempty"` + SnoozeAlarm *SnoozeAlarmResponse `xml:"SnoozeAlarmResponse,omitempty"` + EndDirectControlSession *EndDirectControlSessionResponse `xml:"EndDirectControlSessionResponse,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(``) + 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 SetAVTransportURIArgs struct { + Xmlns string `xml:"xmlns:u,attr"` + InstanceID uint32 `xml:"InstanceID"` + CurrentURI string `xml:"CurrentURI"` + CurrentURIMetaData string `xml:"CurrentURIMetaData"` +} +type SetAVTransportURIResponse struct { +} + +func (s *Service) SetAVTransportURI(httpClient *http.Client, args *SetAVTransportURIArgs) (*SetAVTransportURIResponse, error) { + args.Xmlns = _ServiceURN + r, err := s.exec(`SetAVTransportURI`, httpClient, + &Envelope{ + EncodingStyle: _EncodingSchema, + Xmlns: _EnvelopeSchema, + Body: Body{SetAVTransportURI: args}, + }) + if err != nil { + return nil, err + } + if r.Body.SetAVTransportURI == nil { + return nil, errors.New(`unexpected respose from service calling avtransport.SetAVTransportURI()`) + } + + return r.Body.SetAVTransportURI, nil +} + +type SetNextAVTransportURIArgs struct { + Xmlns string `xml:"xmlns:u,attr"` + InstanceID uint32 `xml:"InstanceID"` + NextURI string `xml:"NextURI"` + NextURIMetaData string `xml:"NextURIMetaData"` +} +type SetNextAVTransportURIResponse struct { +} + +func (s *Service) SetNextAVTransportURI(httpClient *http.Client, args *SetNextAVTransportURIArgs) (*SetNextAVTransportURIResponse, error) { + args.Xmlns = _ServiceURN + r, err := s.exec(`SetNextAVTransportURI`, httpClient, + &Envelope{ + EncodingStyle: _EncodingSchema, + Xmlns: _EnvelopeSchema, + Body: Body{SetNextAVTransportURI: args}, + }) + if err != nil { + return nil, err + } + if r.Body.SetNextAVTransportURI == nil { + return nil, errors.New(`unexpected respose from service calling avtransport.SetNextAVTransportURI()`) + } + + return r.Body.SetNextAVTransportURI, nil +} + +type AddURIToQueueArgs struct { + Xmlns string `xml:"xmlns:u,attr"` + InstanceID uint32 `xml:"InstanceID"` + EnqueuedURI string `xml:"EnqueuedURI"` + EnqueuedURIMetaData string `xml:"EnqueuedURIMetaData"` + DesiredFirstTrackNumberEnqueued uint32 `xml:"DesiredFirstTrackNumberEnqueued"` + EnqueueAsNext bool `xml:"EnqueueAsNext"` +} +type AddURIToQueueResponse struct { + FirstTrackNumberEnqueued uint32 `xml:"FirstTrackNumberEnqueued"` + NumTracksAdded uint32 `xml:"NumTracksAdded"` + NewQueueLength uint32 `xml:"NewQueueLength"` +} + +func (s *Service) AddURIToQueue(httpClient *http.Client, args *AddURIToQueueArgs) (*AddURIToQueueResponse, error) { + args.Xmlns = _ServiceURN + r, err := s.exec(`AddURIToQueue`, httpClient, + &Envelope{ + EncodingStyle: _EncodingSchema, + Xmlns: _EnvelopeSchema, + Body: Body{AddURIToQueue: args}, + }) + if err != nil { + return nil, err + } + if r.Body.AddURIToQueue == nil { + return nil, errors.New(`unexpected respose from service calling avtransport.AddURIToQueue()`) + } + + return r.Body.AddURIToQueue, nil +} + +type AddMultipleURIsToQueueArgs struct { + Xmlns string `xml:"xmlns:u,attr"` + InstanceID uint32 `xml:"InstanceID"` + UpdateID uint32 `xml:"UpdateID"` + NumberOfURIs uint32 `xml:"NumberOfURIs"` + EnqueuedURIs string `xml:"EnqueuedURIs"` + EnqueuedURIsMetaData string `xml:"EnqueuedURIsMetaData"` + ContainerURI string `xml:"ContainerURI"` + ContainerMetaData string `xml:"ContainerMetaData"` + DesiredFirstTrackNumberEnqueued uint32 `xml:"DesiredFirstTrackNumberEnqueued"` + EnqueueAsNext bool `xml:"EnqueueAsNext"` +} +type AddMultipleURIsToQueueResponse struct { + FirstTrackNumberEnqueued uint32 `xml:"FirstTrackNumberEnqueued"` + NumTracksAdded uint32 `xml:"NumTracksAdded"` + NewQueueLength uint32 `xml:"NewQueueLength"` + NewUpdateID uint32 `xml:"NewUpdateID"` +} + +func (s *Service) AddMultipleURIsToQueue(httpClient *http.Client, args *AddMultipleURIsToQueueArgs) (*AddMultipleURIsToQueueResponse, error) { + args.Xmlns = _ServiceURN + r, err := s.exec(`AddMultipleURIsToQueue`, httpClient, + &Envelope{ + EncodingStyle: _EncodingSchema, + Xmlns: _EnvelopeSchema, + Body: Body{AddMultipleURIsToQueue: args}, + }) + if err != nil { + return nil, err + } + if r.Body.AddMultipleURIsToQueue == nil { + return nil, errors.New(`unexpected respose from service calling avtransport.AddMultipleURIsToQueue()`) + } + + return r.Body.AddMultipleURIsToQueue, nil +} + +type ReorderTracksInQueueArgs struct { + Xmlns string `xml:"xmlns:u,attr"` + InstanceID uint32 `xml:"InstanceID"` + StartingIndex uint32 `xml:"StartingIndex"` + NumberOfTracks uint32 `xml:"NumberOfTracks"` + InsertBefore uint32 `xml:"InsertBefore"` + UpdateID uint32 `xml:"UpdateID"` +} +type ReorderTracksInQueueResponse struct { +} + +func (s *Service) ReorderTracksInQueue(httpClient *http.Client, args *ReorderTracksInQueueArgs) (*ReorderTracksInQueueResponse, error) { + args.Xmlns = _ServiceURN + r, err := s.exec(`ReorderTracksInQueue`, httpClient, + &Envelope{ + EncodingStyle: _EncodingSchema, + Xmlns: _EnvelopeSchema, + Body: Body{ReorderTracksInQueue: args}, + }) + if err != nil { + return nil, err + } + if r.Body.ReorderTracksInQueue == nil { + return nil, errors.New(`unexpected respose from service calling avtransport.ReorderTracksInQueue()`) + } + + return r.Body.ReorderTracksInQueue, nil +} + +type RemoveTrackFromQueueArgs struct { + Xmlns string `xml:"xmlns:u,attr"` + InstanceID uint32 `xml:"InstanceID"` + ObjectID string `xml:"ObjectID"` + UpdateID uint32 `xml:"UpdateID"` +} +type RemoveTrackFromQueueResponse struct { +} + +func (s *Service) RemoveTrackFromQueue(httpClient *http.Client, args *RemoveTrackFromQueueArgs) (*RemoveTrackFromQueueResponse, error) { + args.Xmlns = _ServiceURN + r, err := s.exec(`RemoveTrackFromQueue`, httpClient, + &Envelope{ + EncodingStyle: _EncodingSchema, + Xmlns: _EnvelopeSchema, + Body: Body{RemoveTrackFromQueue: args}, + }) + if err != nil { + return nil, err + } + if r.Body.RemoveTrackFromQueue == nil { + return nil, errors.New(`unexpected respose from service calling avtransport.RemoveTrackFromQueue()`) + } + + return r.Body.RemoveTrackFromQueue, nil +} + +type RemoveTrackRangeFromQueueArgs struct { + Xmlns string `xml:"xmlns:u,attr"` + InstanceID uint32 `xml:"InstanceID"` + UpdateID uint32 `xml:"UpdateID"` + StartingIndex uint32 `xml:"StartingIndex"` + NumberOfTracks uint32 `xml:"NumberOfTracks"` +} +type RemoveTrackRangeFromQueueResponse struct { + NewUpdateID uint32 `xml:"NewUpdateID"` +} + +func (s *Service) RemoveTrackRangeFromQueue(httpClient *http.Client, args *RemoveTrackRangeFromQueueArgs) (*RemoveTrackRangeFromQueueResponse, error) { + args.Xmlns = _ServiceURN + r, err := s.exec(`RemoveTrackRangeFromQueue`, httpClient, + &Envelope{ + EncodingStyle: _EncodingSchema, + Xmlns: _EnvelopeSchema, + Body: Body{RemoveTrackRangeFromQueue: args}, + }) + if err != nil { + return nil, err + } + if r.Body.RemoveTrackRangeFromQueue == nil { + return nil, errors.New(`unexpected respose from service calling avtransport.RemoveTrackRangeFromQueue()`) + } + + return r.Body.RemoveTrackRangeFromQueue, nil +} + +type RemoveAllTracksFromQueueArgs struct { + Xmlns string `xml:"xmlns:u,attr"` + InstanceID uint32 `xml:"InstanceID"` +} +type RemoveAllTracksFromQueueResponse struct { +} + +func (s *Service) RemoveAllTracksFromQueue(httpClient *http.Client, args *RemoveAllTracksFromQueueArgs) (*RemoveAllTracksFromQueueResponse, error) { + args.Xmlns = _ServiceURN + r, err := s.exec(`RemoveAllTracksFromQueue`, httpClient, + &Envelope{ + EncodingStyle: _EncodingSchema, + Xmlns: _EnvelopeSchema, + Body: Body{RemoveAllTracksFromQueue: args}, + }) + if err != nil { + return nil, err + } + if r.Body.RemoveAllTracksFromQueue == nil { + return nil, errors.New(`unexpected respose from service calling avtransport.RemoveAllTracksFromQueue()`) + } + + return r.Body.RemoveAllTracksFromQueue, nil +} + +type SaveQueueArgs struct { + Xmlns string `xml:"xmlns:u,attr"` + InstanceID uint32 `xml:"InstanceID"` + Title string `xml:"Title"` + ObjectID string `xml:"ObjectID"` +} +type SaveQueueResponse struct { + AssignedObjectID string `xml:"AssignedObjectID"` +} + +func (s *Service) SaveQueue(httpClient *http.Client, args *SaveQueueArgs) (*SaveQueueResponse, error) { + args.Xmlns = _ServiceURN + r, err := s.exec(`SaveQueue`, httpClient, + &Envelope{ + EncodingStyle: _EncodingSchema, + Xmlns: _EnvelopeSchema, + Body: Body{SaveQueue: args}, + }) + if err != nil { + return nil, err + } + if r.Body.SaveQueue == nil { + return nil, errors.New(`unexpected respose from service calling avtransport.SaveQueue()`) + } + + return r.Body.SaveQueue, nil +} + +type BackupQueueArgs struct { + Xmlns string `xml:"xmlns:u,attr"` + InstanceID uint32 `xml:"InstanceID"` +} +type BackupQueueResponse struct { +} + +func (s *Service) BackupQueue(httpClient *http.Client, args *BackupQueueArgs) (*BackupQueueResponse, error) { + args.Xmlns = _ServiceURN + r, err := s.exec(`BackupQueue`, httpClient, + &Envelope{ + EncodingStyle: _EncodingSchema, + Xmlns: _EnvelopeSchema, + Body: Body{BackupQueue: args}, + }) + if err != nil { + return nil, err + } + if r.Body.BackupQueue == nil { + return nil, errors.New(`unexpected respose from service calling avtransport.BackupQueue()`) + } + + return r.Body.BackupQueue, nil +} + +type CreateSavedQueueArgs struct { + Xmlns string `xml:"xmlns:u,attr"` + InstanceID uint32 `xml:"InstanceID"` + Title string `xml:"Title"` + EnqueuedURI string `xml:"EnqueuedURI"` + EnqueuedURIMetaData string `xml:"EnqueuedURIMetaData"` +} +type CreateSavedQueueResponse struct { + NumTracksAdded uint32 `xml:"NumTracksAdded"` + NewQueueLength uint32 `xml:"NewQueueLength"` + AssignedObjectID string `xml:"AssignedObjectID"` + NewUpdateID uint32 `xml:"NewUpdateID"` +} + +func (s *Service) CreateSavedQueue(httpClient *http.Client, args *CreateSavedQueueArgs) (*CreateSavedQueueResponse, error) { + args.Xmlns = _ServiceURN + r, err := s.exec(`CreateSavedQueue`, httpClient, + &Envelope{ + EncodingStyle: _EncodingSchema, + Xmlns: _EnvelopeSchema, + Body: Body{CreateSavedQueue: args}, + }) + if err != nil { + return nil, err + } + if r.Body.CreateSavedQueue == nil { + return nil, errors.New(`unexpected respose from service calling avtransport.CreateSavedQueue()`) + } + + return r.Body.CreateSavedQueue, nil +} + +type AddURIToSavedQueueArgs struct { + Xmlns string `xml:"xmlns:u,attr"` + InstanceID uint32 `xml:"InstanceID"` + ObjectID string `xml:"ObjectID"` + UpdateID uint32 `xml:"UpdateID"` + EnqueuedURI string `xml:"EnqueuedURI"` + EnqueuedURIMetaData string `xml:"EnqueuedURIMetaData"` + AddAtIndex uint32 `xml:"AddAtIndex"` +} +type AddURIToSavedQueueResponse struct { + NumTracksAdded uint32 `xml:"NumTracksAdded"` + NewQueueLength uint32 `xml:"NewQueueLength"` + NewUpdateID uint32 `xml:"NewUpdateID"` +} + +func (s *Service) AddURIToSavedQueue(httpClient *http.Client, args *AddURIToSavedQueueArgs) (*AddURIToSavedQueueResponse, error) { + args.Xmlns = _ServiceURN + r, err := s.exec(`AddURIToSavedQueue`, httpClient, + &Envelope{ + EncodingStyle: _EncodingSchema, + Xmlns: _EnvelopeSchema, + Body: Body{AddURIToSavedQueue: args}, + }) + if err != nil { + return nil, err + } + if r.Body.AddURIToSavedQueue == nil { + return nil, errors.New(`unexpected respose from service calling avtransport.AddURIToSavedQueue()`) + } + + return r.Body.AddURIToSavedQueue, nil +} + +type ReorderTracksInSavedQueueArgs struct { + Xmlns string `xml:"xmlns:u,attr"` + InstanceID uint32 `xml:"InstanceID"` + ObjectID string `xml:"ObjectID"` + UpdateID uint32 `xml:"UpdateID"` + TrackList string `xml:"TrackList"` + NewPositionList string `xml:"NewPositionList"` +} +type ReorderTracksInSavedQueueResponse struct { + QueueLengthChange int32 `xml:"QueueLengthChange"` + NewQueueLength uint32 `xml:"NewQueueLength"` + NewUpdateID uint32 `xml:"NewUpdateID"` +} + +func (s *Service) ReorderTracksInSavedQueue(httpClient *http.Client, args *ReorderTracksInSavedQueueArgs) (*ReorderTracksInSavedQueueResponse, error) { + args.Xmlns = _ServiceURN + r, err := s.exec(`ReorderTracksInSavedQueue`, httpClient, + &Envelope{ + EncodingStyle: _EncodingSchema, + Xmlns: _EnvelopeSchema, + Body: Body{ReorderTracksInSavedQueue: args}, + }) + if err != nil { + return nil, err + } + if r.Body.ReorderTracksInSavedQueue == nil { + return nil, errors.New(`unexpected respose from service calling avtransport.ReorderTracksInSavedQueue()`) + } + + return r.Body.ReorderTracksInSavedQueue, nil +} + +type GetMediaInfoArgs struct { + Xmlns string `xml:"xmlns:u,attr"` + InstanceID uint32 `xml:"InstanceID"` +} +type GetMediaInfoResponse struct { + NrTracks uint32 `xml:"NrTracks"` + MediaDuration string `xml:"MediaDuration"` + CurrentURI string `xml:"CurrentURI"` + CurrentURIMetaData string `xml:"CurrentURIMetaData"` + NextURI string `xml:"NextURI"` + NextURIMetaData string `xml:"NextURIMetaData"` + PlayMedium string `xml:"PlayMedium"` + RecordMedium string `xml:"RecordMedium"` + WriteStatus string `xml:"WriteStatus"` +} + +func (s *Service) GetMediaInfo(httpClient *http.Client, args *GetMediaInfoArgs) (*GetMediaInfoResponse, error) { + args.Xmlns = _ServiceURN + r, err := s.exec(`GetMediaInfo`, httpClient, + &Envelope{ + EncodingStyle: _EncodingSchema, + Xmlns: _EnvelopeSchema, + Body: Body{GetMediaInfo: args}, + }) + if err != nil { + return nil, err + } + if r.Body.GetMediaInfo == nil { + return nil, errors.New(`unexpected respose from service calling avtransport.GetMediaInfo()`) + } + + return r.Body.GetMediaInfo, nil +} + +type GetTransportInfoArgs struct { + Xmlns string `xml:"xmlns:u,attr"` + InstanceID uint32 `xml:"InstanceID"` +} +type GetTransportInfoResponse struct { + CurrentTransportState string `xml:"CurrentTransportState"` + CurrentTransportStatus string `xml:"CurrentTransportStatus"` + CurrentSpeed string `xml:"CurrentSpeed"` +} + +func (s *Service) GetTransportInfo(httpClient *http.Client, args *GetTransportInfoArgs) (*GetTransportInfoResponse, error) { + args.Xmlns = _ServiceURN + r, err := s.exec(`GetTransportInfo`, httpClient, + &Envelope{ + EncodingStyle: _EncodingSchema, + Xmlns: _EnvelopeSchema, + Body: Body{GetTransportInfo: args}, + }) + if err != nil { + return nil, err + } + if r.Body.GetTransportInfo == nil { + return nil, errors.New(`unexpected respose from service calling avtransport.GetTransportInfo()`) + } + + return r.Body.GetTransportInfo, nil +} + +type GetPositionInfoArgs struct { + Xmlns string `xml:"xmlns:u,attr"` + InstanceID uint32 `xml:"InstanceID"` +} +type GetPositionInfoResponse struct { + Track uint32 `xml:"Track"` + TrackDuration string `xml:"TrackDuration"` + TrackMetaData string `xml:"TrackMetaData"` + TrackURI string `xml:"TrackURI"` + RelTime string `xml:"RelTime"` + AbsTime string `xml:"AbsTime"` + RelCount int32 `xml:"RelCount"` + AbsCount int32 `xml:"AbsCount"` +} + +func (s *Service) GetPositionInfo(httpClient *http.Client, args *GetPositionInfoArgs) (*GetPositionInfoResponse, error) { + args.Xmlns = _ServiceURN + r, err := s.exec(`GetPositionInfo`, httpClient, + &Envelope{ + EncodingStyle: _EncodingSchema, + Xmlns: _EnvelopeSchema, + Body: Body{GetPositionInfo: args}, + }) + if err != nil { + return nil, err + } + if r.Body.GetPositionInfo == nil { + return nil, errors.New(`unexpected respose from service calling avtransport.GetPositionInfo()`) + } + + return r.Body.GetPositionInfo, nil +} + +type GetDeviceCapabilitiesArgs struct { + Xmlns string `xml:"xmlns:u,attr"` + InstanceID uint32 `xml:"InstanceID"` +} +type GetDeviceCapabilitiesResponse struct { + PlayMedia string `xml:"PlayMedia"` + RecMedia string `xml:"RecMedia"` + RecQualityModes string `xml:"RecQualityModes"` +} + +func (s *Service) GetDeviceCapabilities(httpClient *http.Client, args *GetDeviceCapabilitiesArgs) (*GetDeviceCapabilitiesResponse, error) { + args.Xmlns = _ServiceURN + r, err := s.exec(`GetDeviceCapabilities`, httpClient, + &Envelope{ + EncodingStyle: _EncodingSchema, + Xmlns: _EnvelopeSchema, + Body: Body{GetDeviceCapabilities: args}, + }) + if err != nil { + return nil, err + } + if r.Body.GetDeviceCapabilities == nil { + return nil, errors.New(`unexpected respose from service calling avtransport.GetDeviceCapabilities()`) + } + + return r.Body.GetDeviceCapabilities, nil +} + +type GetTransportSettingsArgs struct { + Xmlns string `xml:"xmlns:u,attr"` + InstanceID uint32 `xml:"InstanceID"` +} +type GetTransportSettingsResponse struct { + PlayMode string `xml:"PlayMode"` + RecQualityMode string `xml:"RecQualityMode"` +} + +func (s *Service) GetTransportSettings(httpClient *http.Client, args *GetTransportSettingsArgs) (*GetTransportSettingsResponse, error) { + args.Xmlns = _ServiceURN + r, err := s.exec(`GetTransportSettings`, httpClient, + &Envelope{ + EncodingStyle: _EncodingSchema, + Xmlns: _EnvelopeSchema, + Body: Body{GetTransportSettings: args}, + }) + if err != nil { + return nil, err + } + if r.Body.GetTransportSettings == nil { + return nil, errors.New(`unexpected respose from service calling avtransport.GetTransportSettings()`) + } + + return r.Body.GetTransportSettings, nil +} + +type GetCrossfadeModeArgs struct { + Xmlns string `xml:"xmlns:u,attr"` + InstanceID uint32 `xml:"InstanceID"` +} +type GetCrossfadeModeResponse struct { + CrossfadeMode bool `xml:"CrossfadeMode"` +} + +func (s *Service) GetCrossfadeMode(httpClient *http.Client, args *GetCrossfadeModeArgs) (*GetCrossfadeModeResponse, error) { + args.Xmlns = _ServiceURN + r, err := s.exec(`GetCrossfadeMode`, httpClient, + &Envelope{ + EncodingStyle: _EncodingSchema, + Xmlns: _EnvelopeSchema, + Body: Body{GetCrossfadeMode: args}, + }) + if err != nil { + return nil, err + } + if r.Body.GetCrossfadeMode == nil { + return nil, errors.New(`unexpected respose from service calling avtransport.GetCrossfadeMode()`) + } + + return r.Body.GetCrossfadeMode, 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 avtransport.Stop()`) + } + + return r.Body.Stop, nil +} + +type PlayArgs struct { + Xmlns string `xml:"xmlns:u,attr"` + InstanceID uint32 `xml:"InstanceID"` + // Allowed Value: 1 + 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 avtransport.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 avtransport.Pause()`) + } + + return r.Body.Pause, nil +} + +type SeekArgs struct { + Xmlns string `xml:"xmlns:u,attr"` + InstanceID uint32 `xml:"InstanceID"` + // Allowed Value: TRACK_NR + // Allowed Value: REL_TIME + // Allowed Value: TIME_DELTA + Unit string `xml:"Unit"` + Target string `xml:"Target"` +} +type SeekResponse struct { +} + +func (s *Service) Seek(httpClient *http.Client, args *SeekArgs) (*SeekResponse, error) { + args.Xmlns = _ServiceURN + r, err := s.exec(`Seek`, httpClient, + &Envelope{ + EncodingStyle: _EncodingSchema, + Xmlns: _EnvelopeSchema, + Body: Body{Seek: args}, + }) + if err != nil { + return nil, err + } + if r.Body.Seek == nil { + return nil, errors.New(`unexpected respose from service calling avtransport.Seek()`) + } + + return r.Body.Seek, 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 avtransport.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 avtransport.Previous()`) + } + + return r.Body.Previous, nil +} + +type SetPlayModeArgs struct { + Xmlns string `xml:"xmlns:u,attr"` + InstanceID uint32 `xml:"InstanceID"` + // Allowed Value: NORMAL + // Allowed Value: REPEAT_ALL + // Allowed Value: REPEAT_ONE + // Allowed Value: SHUFFLE_NOREPEAT + // Allowed Value: SHUFFLE + // Allowed Value: SHUFFLE_REPEAT_ONE + NewPlayMode string `xml:"NewPlayMode"` +} +type SetPlayModeResponse struct { +} + +func (s *Service) SetPlayMode(httpClient *http.Client, args *SetPlayModeArgs) (*SetPlayModeResponse, error) { + args.Xmlns = _ServiceURN + r, err := s.exec(`SetPlayMode`, httpClient, + &Envelope{ + EncodingStyle: _EncodingSchema, + Xmlns: _EnvelopeSchema, + Body: Body{SetPlayMode: args}, + }) + if err != nil { + return nil, err + } + if r.Body.SetPlayMode == nil { + return nil, errors.New(`unexpected respose from service calling avtransport.SetPlayMode()`) + } + + return r.Body.SetPlayMode, nil +} + +type SetCrossfadeModeArgs struct { + Xmlns string `xml:"xmlns:u,attr"` + InstanceID uint32 `xml:"InstanceID"` + CrossfadeMode bool `xml:"CrossfadeMode"` +} +type SetCrossfadeModeResponse struct { +} + +func (s *Service) SetCrossfadeMode(httpClient *http.Client, args *SetCrossfadeModeArgs) (*SetCrossfadeModeResponse, error) { + args.Xmlns = _ServiceURN + r, err := s.exec(`SetCrossfadeMode`, httpClient, + &Envelope{ + EncodingStyle: _EncodingSchema, + Xmlns: _EnvelopeSchema, + Body: Body{SetCrossfadeMode: args}, + }) + if err != nil { + return nil, err + } + if r.Body.SetCrossfadeMode == nil { + return nil, errors.New(`unexpected respose from service calling avtransport.SetCrossfadeMode()`) + } + + return r.Body.SetCrossfadeMode, nil +} + +type NotifyDeletedURIArgs struct { + Xmlns string `xml:"xmlns:u,attr"` + InstanceID uint32 `xml:"InstanceID"` + DeletedURI string `xml:"DeletedURI"` +} +type NotifyDeletedURIResponse struct { +} + +func (s *Service) NotifyDeletedURI(httpClient *http.Client, args *NotifyDeletedURIArgs) (*NotifyDeletedURIResponse, error) { + args.Xmlns = _ServiceURN + r, err := s.exec(`NotifyDeletedURI`, httpClient, + &Envelope{ + EncodingStyle: _EncodingSchema, + Xmlns: _EnvelopeSchema, + Body: Body{NotifyDeletedURI: args}, + }) + if err != nil { + return nil, err + } + if r.Body.NotifyDeletedURI == nil { + return nil, errors.New(`unexpected respose from service calling avtransport.NotifyDeletedURI()`) + } + + return r.Body.NotifyDeletedURI, nil +} + +type GetCurrentTransportActionsArgs struct { + Xmlns string `xml:"xmlns:u,attr"` + InstanceID uint32 `xml:"InstanceID"` +} +type GetCurrentTransportActionsResponse struct { + Actions string `xml:"Actions"` +} + +func (s *Service) GetCurrentTransportActions(httpClient *http.Client, args *GetCurrentTransportActionsArgs) (*GetCurrentTransportActionsResponse, error) { + args.Xmlns = _ServiceURN + r, err := s.exec(`GetCurrentTransportActions`, httpClient, + &Envelope{ + EncodingStyle: _EncodingSchema, + Xmlns: _EnvelopeSchema, + Body: Body{GetCurrentTransportActions: args}, + }) + if err != nil { + return nil, err + } + if r.Body.GetCurrentTransportActions == nil { + return nil, errors.New(`unexpected respose from service calling avtransport.GetCurrentTransportActions()`) + } + + return r.Body.GetCurrentTransportActions, nil +} + +type BecomeCoordinatorOfStandaloneGroupArgs struct { + Xmlns string `xml:"xmlns:u,attr"` + InstanceID uint32 `xml:"InstanceID"` +} +type BecomeCoordinatorOfStandaloneGroupResponse struct { + DelegatedGroupCoordinatorID string `xml:"DelegatedGroupCoordinatorID"` + NewGroupID string `xml:"NewGroupID"` +} + +func (s *Service) BecomeCoordinatorOfStandaloneGroup(httpClient *http.Client, args *BecomeCoordinatorOfStandaloneGroupArgs) (*BecomeCoordinatorOfStandaloneGroupResponse, error) { + args.Xmlns = _ServiceURN + r, err := s.exec(`BecomeCoordinatorOfStandaloneGroup`, httpClient, + &Envelope{ + EncodingStyle: _EncodingSchema, + Xmlns: _EnvelopeSchema, + Body: Body{BecomeCoordinatorOfStandaloneGroup: args}, + }) + if err != nil { + return nil, err + } + if r.Body.BecomeCoordinatorOfStandaloneGroup == nil { + return nil, errors.New(`unexpected respose from service calling avtransport.BecomeCoordinatorOfStandaloneGroup()`) + } + + return r.Body.BecomeCoordinatorOfStandaloneGroup, nil +} + +type DelegateGroupCoordinationToArgs struct { + Xmlns string `xml:"xmlns:u,attr"` + InstanceID uint32 `xml:"InstanceID"` + NewCoordinator string `xml:"NewCoordinator"` + RejoinGroup bool `xml:"RejoinGroup"` +} +type DelegateGroupCoordinationToResponse struct { +} + +func (s *Service) DelegateGroupCoordinationTo(httpClient *http.Client, args *DelegateGroupCoordinationToArgs) (*DelegateGroupCoordinationToResponse, error) { + args.Xmlns = _ServiceURN + r, err := s.exec(`DelegateGroupCoordinationTo`, httpClient, + &Envelope{ + EncodingStyle: _EncodingSchema, + Xmlns: _EnvelopeSchema, + Body: Body{DelegateGroupCoordinationTo: args}, + }) + if err != nil { + return nil, err + } + if r.Body.DelegateGroupCoordinationTo == nil { + return nil, errors.New(`unexpected respose from service calling avtransport.DelegateGroupCoordinationTo()`) + } + + return r.Body.DelegateGroupCoordinationTo, nil +} + +type BecomeGroupCoordinatorArgs struct { + Xmlns string `xml:"xmlns:u,attr"` + InstanceID uint32 `xml:"InstanceID"` + CurrentCoordinator string `xml:"CurrentCoordinator"` + CurrentGroupID string `xml:"CurrentGroupID"` + OtherMembers string `xml:"OtherMembers"` + TransportSettings string `xml:"TransportSettings"` + CurrentURI string `xml:"CurrentURI"` + CurrentURIMetaData string `xml:"CurrentURIMetaData"` + SleepTimerState string `xml:"SleepTimerState"` + AlarmState string `xml:"AlarmState"` + StreamRestartState string `xml:"StreamRestartState"` + CurrentQueueTrackList string `xml:"CurrentQueueTrackList"` + CurrentVLIState string `xml:"CurrentVLIState"` +} +type BecomeGroupCoordinatorResponse struct { +} + +func (s *Service) BecomeGroupCoordinator(httpClient *http.Client, args *BecomeGroupCoordinatorArgs) (*BecomeGroupCoordinatorResponse, error) { + args.Xmlns = _ServiceURN + r, err := s.exec(`BecomeGroupCoordinator`, httpClient, + &Envelope{ + EncodingStyle: _EncodingSchema, + Xmlns: _EnvelopeSchema, + Body: Body{BecomeGroupCoordinator: args}, + }) + if err != nil { + return nil, err + } + if r.Body.BecomeGroupCoordinator == nil { + return nil, errors.New(`unexpected respose from service calling avtransport.BecomeGroupCoordinator()`) + } + + return r.Body.BecomeGroupCoordinator, nil +} + +type BecomeGroupCoordinatorAndSourceArgs struct { + Xmlns string `xml:"xmlns:u,attr"` + InstanceID uint32 `xml:"InstanceID"` + CurrentCoordinator string `xml:"CurrentCoordinator"` + CurrentGroupID string `xml:"CurrentGroupID"` + OtherMembers string `xml:"OtherMembers"` + CurrentURI string `xml:"CurrentURI"` + CurrentURIMetaData string `xml:"CurrentURIMetaData"` + SleepTimerState string `xml:"SleepTimerState"` + AlarmState string `xml:"AlarmState"` + StreamRestartState string `xml:"StreamRestartState"` + CurrentAVTTrackList string `xml:"CurrentAVTTrackList"` + CurrentQueueTrackList string `xml:"CurrentQueueTrackList"` + CurrentSourceState string `xml:"CurrentSourceState"` + ResumePlayback bool `xml:"ResumePlayback"` +} +type BecomeGroupCoordinatorAndSourceResponse struct { +} + +func (s *Service) BecomeGroupCoordinatorAndSource(httpClient *http.Client, args *BecomeGroupCoordinatorAndSourceArgs) (*BecomeGroupCoordinatorAndSourceResponse, error) { + args.Xmlns = _ServiceURN + r, err := s.exec(`BecomeGroupCoordinatorAndSource`, httpClient, + &Envelope{ + EncodingStyle: _EncodingSchema, + Xmlns: _EnvelopeSchema, + Body: Body{BecomeGroupCoordinatorAndSource: args}, + }) + if err != nil { + return nil, err + } + if r.Body.BecomeGroupCoordinatorAndSource == nil { + return nil, errors.New(`unexpected respose from service calling avtransport.BecomeGroupCoordinatorAndSource()`) + } + + return r.Body.BecomeGroupCoordinatorAndSource, nil +} + +type ChangeCoordinatorArgs struct { + Xmlns string `xml:"xmlns:u,attr"` + InstanceID uint32 `xml:"InstanceID"` + CurrentCoordinator string `xml:"CurrentCoordinator"` + NewCoordinator string `xml:"NewCoordinator"` + NewTransportSettings string `xml:"NewTransportSettings"` + CurrentAVTransportURI string `xml:"CurrentAVTransportURI"` +} +type ChangeCoordinatorResponse struct { +} + +func (s *Service) ChangeCoordinator(httpClient *http.Client, args *ChangeCoordinatorArgs) (*ChangeCoordinatorResponse, error) { + args.Xmlns = _ServiceURN + r, err := s.exec(`ChangeCoordinator`, httpClient, + &Envelope{ + EncodingStyle: _EncodingSchema, + Xmlns: _EnvelopeSchema, + Body: Body{ChangeCoordinator: args}, + }) + if err != nil { + return nil, err + } + if r.Body.ChangeCoordinator == nil { + return nil, errors.New(`unexpected respose from service calling avtransport.ChangeCoordinator()`) + } + + return r.Body.ChangeCoordinator, nil +} + +type ChangeTransportSettingsArgs struct { + Xmlns string `xml:"xmlns:u,attr"` + InstanceID uint32 `xml:"InstanceID"` + NewTransportSettings string `xml:"NewTransportSettings"` + CurrentAVTransportURI string `xml:"CurrentAVTransportURI"` +} +type ChangeTransportSettingsResponse struct { +} + +func (s *Service) ChangeTransportSettings(httpClient *http.Client, args *ChangeTransportSettingsArgs) (*ChangeTransportSettingsResponse, error) { + args.Xmlns = _ServiceURN + r, err := s.exec(`ChangeTransportSettings`, httpClient, + &Envelope{ + EncodingStyle: _EncodingSchema, + Xmlns: _EnvelopeSchema, + Body: Body{ChangeTransportSettings: args}, + }) + if err != nil { + return nil, err + } + if r.Body.ChangeTransportSettings == nil { + return nil, errors.New(`unexpected respose from service calling avtransport.ChangeTransportSettings()`) + } + + return r.Body.ChangeTransportSettings, nil +} + +type ConfigureSleepTimerArgs struct { + Xmlns string `xml:"xmlns:u,attr"` + InstanceID uint32 `xml:"InstanceID"` + NewSleepTimerDuration string `xml:"NewSleepTimerDuration"` +} +type ConfigureSleepTimerResponse struct { +} + +func (s *Service) ConfigureSleepTimer(httpClient *http.Client, args *ConfigureSleepTimerArgs) (*ConfigureSleepTimerResponse, error) { + args.Xmlns = _ServiceURN + r, err := s.exec(`ConfigureSleepTimer`, httpClient, + &Envelope{ + EncodingStyle: _EncodingSchema, + Xmlns: _EnvelopeSchema, + Body: Body{ConfigureSleepTimer: args}, + }) + if err != nil { + return nil, err + } + if r.Body.ConfigureSleepTimer == nil { + return nil, errors.New(`unexpected respose from service calling avtransport.ConfigureSleepTimer()`) + } + + return r.Body.ConfigureSleepTimer, nil +} + +type GetRemainingSleepTimerDurationArgs struct { + Xmlns string `xml:"xmlns:u,attr"` + InstanceID uint32 `xml:"InstanceID"` +} +type GetRemainingSleepTimerDurationResponse struct { + RemainingSleepTimerDuration string `xml:"RemainingSleepTimerDuration"` + CurrentSleepTimerGeneration uint32 `xml:"CurrentSleepTimerGeneration"` +} + +func (s *Service) GetRemainingSleepTimerDuration(httpClient *http.Client, args *GetRemainingSleepTimerDurationArgs) (*GetRemainingSleepTimerDurationResponse, error) { + args.Xmlns = _ServiceURN + r, err := s.exec(`GetRemainingSleepTimerDuration`, httpClient, + &Envelope{ + EncodingStyle: _EncodingSchema, + Xmlns: _EnvelopeSchema, + Body: Body{GetRemainingSleepTimerDuration: args}, + }) + if err != nil { + return nil, err + } + if r.Body.GetRemainingSleepTimerDuration == nil { + return nil, errors.New(`unexpected respose from service calling avtransport.GetRemainingSleepTimerDuration()`) + } + + return r.Body.GetRemainingSleepTimerDuration, nil +} + +type RunAlarmArgs struct { + Xmlns string `xml:"xmlns:u,attr"` + InstanceID uint32 `xml:"InstanceID"` + AlarmID uint32 `xml:"AlarmID"` + LoggedStartTime string `xml:"LoggedStartTime"` + Duration string `xml:"Duration"` + ProgramURI string `xml:"ProgramURI"` + ProgramMetaData string `xml:"ProgramMetaData"` + // Allowed Value: NORMAL + // Allowed Value: REPEAT_ALL + // Allowed Value: REPEAT_ONE + // Allowed Value: SHUFFLE_NOREPEAT + // Allowed Value: SHUFFLE + // Allowed Value: SHUFFLE_REPEAT_ONE + PlayMode string `xml:"PlayMode"` + Volume uint16 `xml:"Volume"` + IncludeLinkedZones bool `xml:"IncludeLinkedZones"` +} +type RunAlarmResponse struct { +} + +func (s *Service) RunAlarm(httpClient *http.Client, args *RunAlarmArgs) (*RunAlarmResponse, error) { + args.Xmlns = _ServiceURN + r, err := s.exec(`RunAlarm`, httpClient, + &Envelope{ + EncodingStyle: _EncodingSchema, + Xmlns: _EnvelopeSchema, + Body: Body{RunAlarm: args}, + }) + if err != nil { + return nil, err + } + if r.Body.RunAlarm == nil { + return nil, errors.New(`unexpected respose from service calling avtransport.RunAlarm()`) + } + + return r.Body.RunAlarm, nil +} + +type StartAutoplayArgs struct { + Xmlns string `xml:"xmlns:u,attr"` + InstanceID uint32 `xml:"InstanceID"` + ProgramURI string `xml:"ProgramURI"` + ProgramMetaData string `xml:"ProgramMetaData"` + Volume uint16 `xml:"Volume"` + IncludeLinkedZones bool `xml:"IncludeLinkedZones"` + ResetVolumeAfter bool `xml:"ResetVolumeAfter"` +} +type StartAutoplayResponse struct { +} + +func (s *Service) StartAutoplay(httpClient *http.Client, args *StartAutoplayArgs) (*StartAutoplayResponse, error) { + args.Xmlns = _ServiceURN + r, err := s.exec(`StartAutoplay`, httpClient, + &Envelope{ + EncodingStyle: _EncodingSchema, + Xmlns: _EnvelopeSchema, + Body: Body{StartAutoplay: args}, + }) + if err != nil { + return nil, err + } + if r.Body.StartAutoplay == nil { + return nil, errors.New(`unexpected respose from service calling avtransport.StartAutoplay()`) + } + + return r.Body.StartAutoplay, nil +} + +type GetRunningAlarmPropertiesArgs struct { + Xmlns string `xml:"xmlns:u,attr"` + InstanceID uint32 `xml:"InstanceID"` +} +type GetRunningAlarmPropertiesResponse struct { + AlarmID uint32 `xml:"AlarmID"` + GroupID string `xml:"GroupID"` + LoggedStartTime string `xml:"LoggedStartTime"` +} + +func (s *Service) GetRunningAlarmProperties(httpClient *http.Client, args *GetRunningAlarmPropertiesArgs) (*GetRunningAlarmPropertiesResponse, error) { + args.Xmlns = _ServiceURN + r, err := s.exec(`GetRunningAlarmProperties`, httpClient, + &Envelope{ + EncodingStyle: _EncodingSchema, + Xmlns: _EnvelopeSchema, + Body: Body{GetRunningAlarmProperties: args}, + }) + if err != nil { + return nil, err + } + if r.Body.GetRunningAlarmProperties == nil { + return nil, errors.New(`unexpected respose from service calling avtransport.GetRunningAlarmProperties()`) + } + + return r.Body.GetRunningAlarmProperties, nil +} + +type SnoozeAlarmArgs struct { + Xmlns string `xml:"xmlns:u,attr"` + InstanceID uint32 `xml:"InstanceID"` + Duration string `xml:"Duration"` +} +type SnoozeAlarmResponse struct { +} + +func (s *Service) SnoozeAlarm(httpClient *http.Client, args *SnoozeAlarmArgs) (*SnoozeAlarmResponse, error) { + args.Xmlns = _ServiceURN + r, err := s.exec(`SnoozeAlarm`, httpClient, + &Envelope{ + EncodingStyle: _EncodingSchema, + Xmlns: _EnvelopeSchema, + Body: Body{SnoozeAlarm: args}, + }) + if err != nil { + return nil, err + } + if r.Body.SnoozeAlarm == nil { + return nil, errors.New(`unexpected respose from service calling avtransport.SnoozeAlarm()`) + } + + return r.Body.SnoozeAlarm, nil +} + +type EndDirectControlSessionArgs struct { + Xmlns string `xml:"xmlns:u,attr"` + InstanceID uint32 `xml:"InstanceID"` +} +type EndDirectControlSessionResponse struct { +} + +func (s *Service) EndDirectControlSession(httpClient *http.Client, args *EndDirectControlSessionArgs) (*EndDirectControlSessionResponse, error) { + args.Xmlns = _ServiceURN + r, err := s.exec(`EndDirectControlSession`, httpClient, + &Envelope{ + EncodingStyle: _EncodingSchema, + Xmlns: _EnvelopeSchema, + Body: Body{EndDirectControlSession: args}, + }) + if err != nil { + return nil, err + } + if r.Body.EndDirectControlSession == nil { + return nil, errors.New(`unexpected respose from service calling avtransport.EndDirectControlSession()`) + } + + return r.Body.EndDirectControlSession, nil +} diff --git a/vendor/github.com/szatmary/sonos/AlarmClock/AlarmClock.go b/vendor/github.com/szatmary/sonos/AlarmClock/AlarmClock.go new file mode 100644 index 0000000..9131a55 --- /dev/null +++ b/vendor/github.com/szatmary/sonos/AlarmClock/AlarmClock.go @@ -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(``) + 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 +} diff --git a/vendor/github.com/szatmary/sonos/ConnectionManager/ConnectionManager.go b/vendor/github.com/szatmary/sonos/ConnectionManager/ConnectionManager.go new file mode 100644 index 0000000..986ae93 --- /dev/null +++ b/vendor/github.com/szatmary/sonos/ConnectionManager/ConnectionManager.go @@ -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(``) + 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 +} diff --git a/vendor/github.com/szatmary/sonos/ContentDirectory/ContentDirectory.go b/vendor/github.com/szatmary/sonos/ContentDirectory/ContentDirectory.go new file mode 100644 index 0000000..87e05c0 --- /dev/null +++ b/vendor/github.com/szatmary/sonos/ContentDirectory/ContentDirectory.go @@ -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(``) + 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 +} diff --git a/vendor/github.com/szatmary/sonos/DeviceProperties/DeviceProperties.go b/vendor/github.com/szatmary/sonos/DeviceProperties/DeviceProperties.go new file mode 100644 index 0000000..76638e5 --- /dev/null +++ b/vendor/github.com/szatmary/sonos/DeviceProperties/DeviceProperties.go @@ -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(``) + 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 +} diff --git a/vendor/github.com/szatmary/sonos/GroupManagement/GroupManagement.go b/vendor/github.com/szatmary/sonos/GroupManagement/GroupManagement.go new file mode 100644 index 0000000..3720577 --- /dev/null +++ b/vendor/github.com/szatmary/sonos/GroupManagement/GroupManagement.go @@ -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(``) + 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 +} diff --git a/vendor/github.com/szatmary/sonos/GroupRenderingControl/GroupRenderingControl.go b/vendor/github.com/szatmary/sonos/GroupRenderingControl/GroupRenderingControl.go new file mode 100644 index 0000000..bd823b8 --- /dev/null +++ b/vendor/github.com/szatmary/sonos/GroupRenderingControl/GroupRenderingControl.go @@ -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(``) + 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 +} diff --git a/vendor/github.com/szatmary/sonos/LICENSE b/vendor/github.com/szatmary/sonos/LICENSE new file mode 100644 index 0000000..1f49b97 --- /dev/null +++ b/vendor/github.com/szatmary/sonos/LICENSE @@ -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. diff --git a/vendor/github.com/szatmary/sonos/MusicServices/MusicServices.go b/vendor/github.com/szatmary/sonos/MusicServices/MusicServices.go new file mode 100644 index 0000000..48d0926 --- /dev/null +++ b/vendor/github.com/szatmary/sonos/MusicServices/MusicServices.go @@ -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(``) + 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 +} diff --git a/vendor/github.com/szatmary/sonos/QPlay/QPlay.go b/vendor/github.com/szatmary/sonos/QPlay/QPlay.go new file mode 100644 index 0000000..7f4af92 --- /dev/null +++ b/vendor/github.com/szatmary/sonos/QPlay/QPlay.go @@ -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(``) + 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 +} diff --git a/vendor/github.com/szatmary/sonos/Queue/Queue.go b/vendor/github.com/szatmary/sonos/Queue/Queue.go new file mode 100644 index 0000000..4c6f026 --- /dev/null +++ b/vendor/github.com/szatmary/sonos/Queue/Queue.go @@ -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(``) + 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 +} diff --git a/vendor/github.com/szatmary/sonos/README.md b/vendor/github.com/szatmary/sonos/README.md new file mode 100644 index 0000000..e69de29 diff --git a/vendor/github.com/szatmary/sonos/RenderingControl/RenderingControl.go b/vendor/github.com/szatmary/sonos/RenderingControl/RenderingControl.go new file mode 100644 index 0000000..8dd78de --- /dev/null +++ b/vendor/github.com/szatmary/sonos/RenderingControl/RenderingControl.go @@ -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(``) + 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 +} diff --git a/vendor/github.com/szatmary/sonos/SystemProperties/SystemProperties.go b/vendor/github.com/szatmary/sonos/SystemProperties/SystemProperties.go new file mode 100644 index 0000000..c099216 --- /dev/null +++ b/vendor/github.com/szatmary/sonos/SystemProperties/SystemProperties.go @@ -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(``) + 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 +} diff --git a/vendor/github.com/szatmary/sonos/VirtualLineIn/VirtualLineIn.go b/vendor/github.com/szatmary/sonos/VirtualLineIn/VirtualLineIn.go new file mode 100644 index 0000000..508579d --- /dev/null +++ b/vendor/github.com/szatmary/sonos/VirtualLineIn/VirtualLineIn.go @@ -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(``) + 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 +} diff --git a/vendor/github.com/szatmary/sonos/ZoneGroupTopology/ZoneGroupTopology.go b/vendor/github.com/szatmary/sonos/ZoneGroupTopology/ZoneGroupTopology.go new file mode 100644 index 0000000..2bc1887 --- /dev/null +++ b/vendor/github.com/szatmary/sonos/ZoneGroupTopology/ZoneGroupTopology.go @@ -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(``) + 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 +} diff --git a/vendor/github.com/szatmary/sonos/sonos.go b/vendor/github.com/szatmary/sonos/sonos.go new file mode 100644 index 0000000..524bcd2 --- /dev/null +++ b/vendor/github.com/szatmary/sonos/sonos.go @@ -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 + } + } + } +} diff --git a/vendor/github.com/szatmary/sonos/zonegroups.go b/vendor/github.com/szatmary/sonos/zonegroups.go new file mode 100644 index 0000000..3a80aaa --- /dev/null +++ b/vendor/github.com/szatmary/sonos/zonegroups.go @@ -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"` +} diff --git a/vendor/github.com/szatmary/sonos/zoneplayer.go b/vendor/github.com/szatmary/sonos/zoneplayer.go new file mode 100644 index 0000000..1b87f60 --- /dev/null +++ b/vendor/github.com/szatmary/sonos/zoneplayer.go @@ -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 +} diff --git a/vendor/modules.txt b/vendor/modules.txt index e29eff9..49c8ce7 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -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