Adds URL templates to integration with Hass
This commit is contained in:
+28
-16
@@ -32,20 +32,32 @@ func initAPI() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if streams.Has(v.Name) {
|
// we can get three types of links:
|
||||||
stream := streams.Get(v.Name)
|
// 1. link to go2rtc stream: rtsp://...:8554/{stream_name}
|
||||||
stream.SetSource(v.Channels.First.Url)
|
// 2. static link to Hass camera
|
||||||
} else {
|
// 3. dynamic link to Hass camera
|
||||||
streams.New(v.Name, v.Channels.First.Url)
|
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)
|
ok(w, r)
|
||||||
|
|
||||||
// /stream/{id}/channel/0/webrtc
|
// /stream/{id}/channel/0/webrtc
|
||||||
default:
|
default:
|
||||||
i := strings.IndexByte(r.RequestURI[8:], '/')
|
i := strings.IndexByte(r.RequestURI[8:], '/')
|
||||||
src := r.RequestURI[8 : 8+i]
|
name := r.RequestURI[8 : 8+i]
|
||||||
if !streams.Has(src) {
|
|
||||||
|
stream := streams.Get(name)
|
||||||
|
if stream == nil {
|
||||||
w.WriteHeader(http.StatusNotFound)
|
w.WriteHeader(http.StatusNotFound)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -62,15 +74,6 @@ func initAPI() {
|
|||||||
return
|
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())
|
s, err = webrtc.ExchangeSDP(stream, string(offer), r.UserAgent())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msg("[api.hass] exchange SDP")
|
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 {
|
type addJSON struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Channels struct {
|
Channels struct {
|
||||||
|
|||||||
+11
-1
@@ -2,6 +2,7 @@ package streams
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/AlexxIT/go2rtc/pkg/streamer"
|
"github.com/AlexxIT/go2rtc/pkg/streamer"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -17,7 +18,9 @@ const (
|
|||||||
type Producer struct {
|
type Producer struct {
|
||||||
streamer.Element
|
streamer.Element
|
||||||
|
|
||||||
url string
|
url string
|
||||||
|
template string
|
||||||
|
|
||||||
element streamer.Producer
|
element streamer.Producer
|
||||||
tracks []*streamer.Track
|
tracks []*streamer.Track
|
||||||
|
|
||||||
@@ -25,6 +28,13 @@ type Producer struct {
|
|||||||
mx sync.Mutex
|
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 {
|
func (p *Producer) GetMedias() []*streamer.Media {
|
||||||
p.mx.Lock()
|
p.mx.Lock()
|
||||||
defer p.mx.Unlock()
|
defer p.mx.Unlock()
|
||||||
|
|||||||
@@ -17,30 +17,33 @@ type Stream struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewStream(source interface{}) *Stream {
|
func NewStream(source interface{}) *Stream {
|
||||||
s := new(Stream)
|
|
||||||
|
|
||||||
switch source := source.(type) {
|
switch source := source.(type) {
|
||||||
case string:
|
case string:
|
||||||
|
s := new(Stream)
|
||||||
prod := &Producer{url: source}
|
prod := &Producer{url: source}
|
||||||
s.producers = append(s.producers, prod)
|
s.producers = append(s.producers, prod)
|
||||||
|
return s
|
||||||
case []interface{}:
|
case []interface{}:
|
||||||
|
s := new(Stream)
|
||||||
for _, source := range source {
|
for _, source := range source {
|
||||||
prod := &Producer{url: source.(string)}
|
prod := &Producer{url: source.(string)}
|
||||||
s.producers = append(s.producers, prod)
|
s.producers = append(s.producers, prod)
|
||||||
}
|
}
|
||||||
|
return s
|
||||||
|
case *Stream:
|
||||||
|
return source
|
||||||
case map[string]interface{}:
|
case map[string]interface{}:
|
||||||
return NewStream(source["url"])
|
return NewStream(source["url"])
|
||||||
case nil:
|
case nil:
|
||||||
|
return new(Stream)
|
||||||
default:
|
default:
|
||||||
panic("wrong source type")
|
panic("wrong source type")
|
||||||
}
|
}
|
||||||
|
|
||||||
return s
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Stream) SetSource(source string) {
|
func (s *Stream) SetSource(source string) {
|
||||||
if len(s.producers) > 0 {
|
for _, prod := range s.producers {
|
||||||
s.producers[0].url = source
|
prod.SetSource(source)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+12
-25
@@ -4,7 +4,6 @@ import (
|
|||||||
"github.com/AlexxIT/go2rtc/cmd/app"
|
"github.com/AlexxIT/go2rtc/cmd/app"
|
||||||
"github.com/AlexxIT/go2rtc/cmd/app/store"
|
"github.com/AlexxIT/go2rtc/cmd/app/store"
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func Init() {
|
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 {
|
if stream, ok := streams[src]; ok {
|
||||||
return stream
|
return stream
|
||||||
}
|
}
|
||||||
@@ -35,30 +44,8 @@ func Get(src string) *Stream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
log.Info().Str("url", src).Msg("[streams] create new 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 New(src, src)
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func Delete(name string) {
|
func Delete(name string) {
|
||||||
|
|||||||
Reference in New Issue
Block a user