fixes doorbird backchannel audio:

- proper session handling
- honor http status codes
- prevent device from being flooded by limiting concurrent audio channels
This commit is contained in:
Oliver Eiber
2025-07-03 23:35:58 +02:00
parent a4d7fd0d95
commit c68e3cafe4
2 changed files with 60 additions and 9 deletions
+55 -9
View File
@@ -1,21 +1,32 @@
package doorbird package doorbird
import ( import (
"bufio"
"fmt" "fmt"
"net" "net"
"net/url" "net/url"
"strconv"
"strings"
"time" "time"
"github.com/AlexxIT/go2rtc/pkg/core" "github.com/AlexxIT/go2rtc/pkg/core"
"github.com/pion/rtp" "github.com/pion/rtp"
) )
var (
clt Client
)
type Client struct { type Client struct {
core.Connection core.Connection
conn net.Conn conn net.Conn
} }
func Dial(rawURL string) (*Client, error) { func Dial(rawURL string) (*Client, error) {
if clt.conn != nil {
return &clt, nil
}
u, err := url.Parse(rawURL) u, err := url.Parse(rawURL)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -45,6 +56,23 @@ func Dial(rawURL string) (*Client, error) {
return nil, err return nil, err
} }
reader := bufio.NewReader(conn)
statusLine, _ := reader.ReadString('\n')
parts := strings.SplitN(statusLine, " ", 3)
if len(parts) >= 2 {
statusCode, err := strconv.Atoi(parts[1])
if err == nil {
if statusCode == 204 {
conn.Close()
return nil, fmt.Errorf("DoorBird user has no api permission: %d", statusCode)
}
if statusCode == 503 {
conn.Close()
return nil, fmt.Errorf("DoorBird device is busy: %d", statusCode)
}
}
}
medias := []*core.Media{ medias := []*core.Media{
{ {
Kind: core.KindAudio, Kind: core.KindAudio,
@@ -55,17 +83,19 @@ func Dial(rawURL string) (*Client, error) {
}, },
} }
return &Client{ clt = Client{
core.Connection{ core.Connection{
ID: core.NewID(), ID: core.NewID(),
FormatName: "doorbird", FormatName: "doorbird",
Protocol: "http", Protocol: "http",
URL: rawURL, URL: rawURL,
Medias: medias, Medias: medias,
Transport: conn, // Transport: conn,
}, },
conn, conn,
}, nil }
return &clt, nil
} }
func (c *Client) GetTrack(media *core.Media, codec *core.Codec) (*core.Receiver, error) { func (c *Client) GetTrack(media *core.Media, codec *core.Codec) (*core.Receiver, error) {
@@ -73,12 +103,18 @@ func (c *Client) GetTrack(media *core.Media, codec *core.Codec) (*core.Receiver,
} }
func (c *Client) AddTrack(media *core.Media, codec *core.Codec, track *core.Receiver) error { func (c *Client) AddTrack(media *core.Media, codec *core.Codec, track *core.Receiver) error {
if len(c.Senders) > 0 {
return fmt.Errorf("DoorBird backchannel already in use")
}
sender := core.NewSender(media, track.Codec) sender := core.NewSender(media, track.Codec)
sender.Handler = func(pkt *rtp.Packet) { sender.Handler = func(pkt *rtp.Packet) {
_ = c.conn.SetWriteDeadline(time.Now().Add(core.ConnDeadline)) if c.conn != nil {
if n, err := c.conn.Write(pkt.Payload); err == nil { _ = c.conn.SetWriteDeadline(time.Now().Add(core.ConnDeadline))
c.Send += n if n, err := c.conn.Write(pkt.Payload); err == nil {
c.Send += n
}
} }
} }
@@ -87,7 +123,17 @@ func (c *Client) AddTrack(media *core.Media, codec *core.Codec, track *core.Rece
return nil return nil
} }
func (c *Client) Start() (err error) { func (c *Client) Start() error {
_, err = c.conn.Read(nil) if c.conn == nil {
return return nil
}
buf := make([]byte, 1)
for {
_, err := c.conn.Read(buf)
if err != nil {
c.conn.Close()
c.conn = nil
return err
}
}
} }
+5
View File
@@ -0,0 +1,5 @@
package doorbird
import "sync"
var backchannelMu sync.Mutex