From 407ccc45bc1ebe41c4153cc55d51cc5a7a904d8d Mon Sep 17 00:00:00 2001 From: Alexey Khit Date: Fri, 16 Sep 2022 17:03:03 +0300 Subject: [PATCH] Adds URL templates to integration with Hass --- cmd/hass/api.go | 44 ++++++++++++++++++++++++++--------------- cmd/streams/producer.go | 12 ++++++++++- cmd/streams/stream.go | 15 ++++++++------ cmd/streams/streams.go | 37 +++++++++++----------------------- 4 files changed, 60 insertions(+), 48 deletions(-) diff --git a/cmd/hass/api.go b/cmd/hass/api.go index 592838ef..776a71da 100644 --- a/cmd/hass/api.go +++ b/cmd/hass/api.go @@ -32,20 +32,32 @@ func initAPI() { return } - if streams.Has(v.Name) { - stream := streams.Get(v.Name) - stream.SetSource(v.Channels.First.Url) - } else { - streams.New(v.Name, v.Channels.First.Url) + // we can get three types of links: + // 1. link to go2rtc stream: rtsp://...:8554/{stream_name} + // 2. static link to Hass camera + // 3. dynamic link to Hass camera + stream := streams.Get(v.Name) + if stream == nil { + // check if it is rtsp link to go2rtc + stream = rtspStream(v.Channels.First.Url) + if stream != nil { + streams.New(v.Name, stream) + } else { + stream = streams.New(v.Name, "{input}") + } } + stream.SetSource(v.Channels.First.Url) + ok(w, r) // /stream/{id}/channel/0/webrtc default: i := strings.IndexByte(r.RequestURI[8:], '/') - src := r.RequestURI[8 : 8+i] - if !streams.Has(src) { + name := r.RequestURI[8 : 8+i] + + stream := streams.Get(name) + if stream == nil { w.WriteHeader(http.StatusNotFound) return } @@ -62,15 +74,6 @@ func initAPI() { return } - // check if stream links to our rtsp server - //if strings.HasPrefix(src, "rtsp://") { - // i := strings.IndexByte(src[7:], '/') - // if i > 0 && streams.Has(src[8+i:]) { - // src = src[8+i:] - // } - //} - - stream := streams.Get(src) s, err = webrtc.ExchangeSDP(stream, string(offer), r.UserAgent()) if err != nil { log.Error().Err(err).Msg("[api.hass] exchange SDP") @@ -83,6 +86,15 @@ func initAPI() { }) } +func rtspStream(url string) *streams.Stream { + if strings.HasPrefix(url, "rtsp://") { + if i := strings.IndexByte(url[7:], '/'); i > 0 { + return streams.Get(url[8+i:]) + } + } + return nil +} + type addJSON struct { Name string `json:"name"` Channels struct { diff --git a/cmd/streams/producer.go b/cmd/streams/producer.go index f2655323..c6f8adb8 100644 --- a/cmd/streams/producer.go +++ b/cmd/streams/producer.go @@ -2,6 +2,7 @@ package streams import ( "github.com/AlexxIT/go2rtc/pkg/streamer" + "strings" "sync" ) @@ -17,7 +18,9 @@ const ( type Producer struct { streamer.Element - url string + url string + template string + element streamer.Producer tracks []*streamer.Track @@ -25,6 +28,13 @@ type Producer struct { mx sync.Mutex } +func (p *Producer) SetSource(s string) { + if p.template == "" { + p.template = p.url + } + p.url = strings.Replace(p.template, "{input}", s, 1) +} + func (p *Producer) GetMedias() []*streamer.Media { p.mx.Lock() defer p.mx.Unlock() diff --git a/cmd/streams/stream.go b/cmd/streams/stream.go index f636c590..b96de8c2 100644 --- a/cmd/streams/stream.go +++ b/cmd/streams/stream.go @@ -17,30 +17,33 @@ type Stream struct { } func NewStream(source interface{}) *Stream { - s := new(Stream) - switch source := source.(type) { case string: + s := new(Stream) prod := &Producer{url: source} s.producers = append(s.producers, prod) + return s case []interface{}: + s := new(Stream) for _, source := range source { prod := &Producer{url: source.(string)} s.producers = append(s.producers, prod) } + return s + case *Stream: + return source case map[string]interface{}: return NewStream(source["url"]) case nil: + return new(Stream) default: panic("wrong source type") } - - return s } func (s *Stream) SetSource(source string) { - if len(s.producers) > 0 { - s.producers[0].url = source + for _, prod := range s.producers { + prod.SetSource(source) } } diff --git a/cmd/streams/streams.go b/cmd/streams/streams.go index 4b629bab..aeda7a7e 100644 --- a/cmd/streams/streams.go +++ b/cmd/streams/streams.go @@ -4,7 +4,6 @@ import ( "github.com/AlexxIT/go2rtc/cmd/app" "github.com/AlexxIT/go2rtc/cmd/app/store" "github.com/rs/zerolog" - "strings" ) func Init() { @@ -25,7 +24,17 @@ func Init() { } } -func Get(src string) *Stream { +func Get(name string) *Stream { + return streams[name] +} + +func New(name string, source interface{}) *Stream { + stream := NewStream(source) + streams[name] = stream + return stream +} + +func GetOrNew(src string) *Stream { if stream, ok := streams[src]; ok { return stream } @@ -35,30 +44,8 @@ func Get(src string) *Stream { } log.Info().Str("url", src).Msg("[streams] create new stream") - stream := NewStream(src) - streams[src] = stream - return stream -} -func Has(src string) bool { - return streams[src] != nil -} - -func New(name string, source interface{}) { - switch source := source.(type) { - case string: - // check if new stream already link on our other stream - if strings.HasPrefix(source, "rtsp://") { - if i := strings.IndexByte(source[7:], '/'); i > 0 { - if stream, ok := streams[source[8+i:]]; ok { - streams[name] = stream - return - } - } - } - } - - streams[name] = NewStream(source) + return New(src, src) } func Delete(name string) {