add sonos handler to play file
This commit is contained in:
1 parent
b7e7db4127
commit
783aa5fd79
44 files changed
+12187
-14
No files matched your search
@@ -12,6 +12,7 @@ type Config struct {
|
||||
AudioOut ConfigAudioOutputStream `arg:"group:AudioOut"`
|
||||
AudioIn ConfigAudioInputStream `arg:"group:AudioIn"`
|
||||
Logging ConfigLogging `arg:"group:Logging"`
|
||||
Ring ConfigRing `arg:"group:Ring"`
|
||||
Http ConfigHTTP `arg:"group:Http"`
|
||||
}
|
||||
|
||||
@@ -25,6 +26,14 @@ type ConfigLogging struct {
|
||||
Level string `arg:"--log-level,env:LOG_LEVEL" default:"debug"`
|
||||
}
|
||||
|
||||
type ConfigRing struct {
|
||||
Device string `arg:"--input-device,env:INPUT_DEVICE" default:"/dev/input/by-path/platform-gpio-keys-user-event"`
|
||||
Key string `arg:"--ring-key" default:"KEY_F1"`
|
||||
JingleName string `arg:"--jingle-name,env:JINGLE_NAME" default:"ding-dong.wav"`
|
||||
JinglePath *string `arg:"--jingle-path,env:JINGLE_PATH"`
|
||||
SonosTarget string `arg:"--sonos-target,env:SONOS_TARGET" default:"Living Room"`
|
||||
}
|
||||
|
||||
type ConfigHTTP struct {
|
||||
Host string `arg:"--http-host,env:HTTP_HOST" default:"0.0.0.0"`
|
||||
Port uint `arg:"--http-port,env:HTTP_PORT" default:"8080"`
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
package ring
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/url"
|
||||
|
||||
"github.com/holoplot/go-evdev"
|
||||
"github.com/kaedwen/webrtc/pkg/common"
|
||||
"github.com/kaedwen/webrtc/pkg/ring/sonos"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type Player interface {
|
||||
Play(uri *url.URL) error
|
||||
}
|
||||
|
||||
type RingHandler struct {
|
||||
lg *zap.Logger
|
||||
cfg *common.ConfigRing
|
||||
players []Player
|
||||
}
|
||||
|
||||
func NewRingHandler(lg *zap.Logger, cfg *common.ConfigRing) (*RingHandler, error) {
|
||||
sp, err := sonos.NewSonosPlayer(lg.With(zap.String("context", "sonos")), cfg.SonosTarget)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &RingHandler{lg, cfg, []Player{sp}}, nil
|
||||
}
|
||||
|
||||
func (h *RingHandler) Watch(ctx context.Context) error {
|
||||
d, err := evdev.Open(h.cfg.Device)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
vMajor, vMinor, vMicro := d.DriverVersion()
|
||||
h.lg.Info("input driver running", zap.String("version", fmt.Sprintf("%d.%d.%d", vMajor, vMinor, vMicro)))
|
||||
|
||||
key := evdev.KEYFromString[h.cfg.Key]
|
||||
|
||||
bu := url.URL{
|
||||
Scheme: "http",
|
||||
Host: "192.168.60.141:9099",
|
||||
}
|
||||
|
||||
go func() {
|
||||
err := d.NonBlock()
|
||||
if err != nil {
|
||||
h.lg.Fatal("failed to set non block", zap.Error(err))
|
||||
}
|
||||
|
||||
for {
|
||||
e, err := d.ReadOne()
|
||||
if err == nil && e.Code == key && e.Value == 0 {
|
||||
tu := bu.JoinPath(h.cfg.JingleName)
|
||||
for _, p := range h.players {
|
||||
if err := p.Play(tu); err != nil {
|
||||
h.lg.Error("failed to play", zap.Error(err))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
<-ctx.Done()
|
||||
_ = d.Close()
|
||||
}()
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package sonos
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
so "github.com/szatmary/sonos"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type SonosPlayer struct {
|
||||
lg *zap.Logger
|
||||
zp *so.ZonePlayer
|
||||
}
|
||||
|
||||
func NewSonosPlayer(lg *zap.Logger, target string) (*SonosPlayer, error) {
|
||||
zp, err := SearchTarget(lg, target)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &SonosPlayer{lg, zp}, nil
|
||||
}
|
||||
|
||||
func (p *SonosPlayer) Play(uri *url.URL) error {
|
||||
err := p.zp.SetAVTransportURI(uri.String())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return p.zp.Play()
|
||||
}
|
||||
|
||||
func SearchTarget(lg *zap.Logger, target string) (*so.ZonePlayer, error) {
|
||||
son, err := so.NewSonos()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer son.Close()
|
||||
|
||||
found, _ := son.Search()
|
||||
to := time.After(10 * time.Second)
|
||||
for {
|
||||
select {
|
||||
case <-to:
|
||||
return nil, errors.New("timeout")
|
||||
case zp := <-found:
|
||||
lg.Info("found player", zap.String("name", zp.RoomName()))
|
||||
if zp.RoomName() == target {
|
||||
return zp, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+7
-7
@@ -25,7 +25,7 @@ type SignalingHandle struct {
|
||||
type HttpServer struct {
|
||||
http.Server
|
||||
lg *zap.Logger
|
||||
cfg *common.ConfigHTTP
|
||||
cfg *common.Config
|
||||
Hndl chan *SignalingHandle
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ func NewSignalingHandle(id string) SignalingHandle {
|
||||
}
|
||||
}
|
||||
|
||||
func NewHttpServer(lg *zap.Logger, cfg *common.ConfigHTTP) *HttpServer {
|
||||
func NewHttpServer(lg *zap.Logger, cfg *common.Config) *HttpServer {
|
||||
h := HttpServer{
|
||||
Hndl: make(chan *SignalingHandle, 10),
|
||||
cfg: cfg,
|
||||
@@ -57,12 +57,12 @@ func NewHttpServer(lg *zap.Logger, cfg *common.ConfigHTTP) *HttpServer {
|
||||
}
|
||||
|
||||
func (h *HttpServer) ListenAndServe(ctx context.Context) error {
|
||||
if h.cfg.Tls {
|
||||
if h.cfg.Http.Tls {
|
||||
// set the configured address
|
||||
h.Addr = h.cfg.Address()
|
||||
h.Addr = h.cfg.Http.Address()
|
||||
|
||||
if h.cfg.TlsCert != nil && h.cfg.TlsKey != nil {
|
||||
cert, err := tls.LoadX509KeyPair(*h.cfg.TlsCert, *h.cfg.TlsKey)
|
||||
if h.cfg.Http.TlsCert != nil && h.cfg.Http.TlsKey != nil {
|
||||
cert, err := tls.LoadX509KeyPair(*h.cfg.Http.TlsCert, *h.cfg.Http.TlsKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -94,7 +94,7 @@ func (h *HttpServer) ListenAndServe(ctx context.Context) error {
|
||||
}()
|
||||
} else {
|
||||
// set the configured address
|
||||
h.Addr = h.cfg.Address()
|
||||
h.Addr = h.cfg.Http.Address()
|
||||
|
||||
go func() {
|
||||
// and listen
|
||||
|
||||
Reference in new issue
Block a user