Code refactoring for SwitchBot format support #1629

This commit is contained in:
Alex X
2025-03-09 18:44:32 +03:00
parent 47b740ff35
commit 117d767f05
3 changed files with 57 additions and 82 deletions

View File

@@ -41,7 +41,7 @@ func streamsHandler(rawURL string) (core.Producer, error) {
// https://aws.amazon.com/kinesis/video-streams/ // https://aws.amazon.com/kinesis/video-streams/
// https://docs.aws.amazon.com/kinesisvideostreams-webrtc-dg/latest/devguide/what-is-kvswebrtc.html // https://docs.aws.amazon.com/kinesisvideostreams-webrtc-dg/latest/devguide/what-is-kvswebrtc.html
// https://github.com/orgs/awslabs/repositories?q=kinesis+webrtc // https://github.com/orgs/awslabs/repositories?q=kinesis+webrtc
return kinesisClient(rawURL, query, "webrtc/kinesis", &kinesisClientOpts{}) return kinesisClient(rawURL, query, "webrtc/kinesis", nil)
} else if format == "openipc" { } else if format == "openipc" {
return openIPCClient(rawURL, query) return openIPCClient(rawURL, query)
} else if format == "switchbot" { } else if format == "switchbot" {

View File

@@ -34,12 +34,10 @@ func (k kinesisResponse) String() string {
return fmt.Sprintf("type=%s, payload=%s", k.Type, k.Payload) return fmt.Sprintf("type=%s, payload=%s", k.Type, k.Payload)
} }
type kinesisClientOpts struct { func kinesisClient(
SessionDescriptionModifier func(*pion.SessionDescription) ([]byte, error) rawURL string, query url.Values, format string,
MediaModifier func() ([]*core.Media, error) sdpOffer func(prod *webrtc.Conn, query url.Values) (any, error),
} ) (core.Producer, error) {
func kinesisClient(rawURL string, query url.Values, format string, opts *kinesisClientOpts) (core.Producer, error) {
// 1. Connect to signalign server // 1. Connect to signalign server
conn, _, err := websocket.DefaultDialer.Dial(rawURL, nil) conn, _, err := websocket.DefaultDialer.Dial(rawURL, nil)
if err != nil { if err != nil {
@@ -113,34 +111,33 @@ func kinesisClient(rawURL string, query url.Values, format string, opts *kinesis
} }
}) })
medias := []*core.Media{ var payload any
{Kind: core.KindVideo, Direction: core.DirectionRecvonly},
{Kind: core.KindAudio, Direction: core.DirectionRecvonly}, if sdpOffer == nil {
} medias := []*core.Media{
if opts.MediaModifier != nil { {Kind: core.KindVideo, Direction: core.DirectionRecvonly},
medias, err = opts.MediaModifier() {Kind: core.KindAudio, Direction: core.DirectionRecvonly},
if err != nil { }
// 4. Create offer
var offer string
if offer, err = prod.CreateOffer(medias); err != nil {
return nil, err
}
// 5. Send offer
payload = pion.SessionDescription{
Type: pion.SDPTypeOffer,
SDP: offer,
}
} else {
if payload, err = sdpOffer(prod, query); err != nil {
return nil, err return nil, err
} }
} }
// 4. Create offer
offer, err := prod.CreateOffer(medias)
if err != nil {
return nil, err
}
// 5. Send offer
req.Action = "SDP_OFFER" req.Action = "SDP_OFFER"
sessionDescription := pion.SessionDescription{ req.Payload, _ = json.Marshal(payload)
Type: pion.SDPTypeOffer,
SDP: offer,
}
if opts.SessionDescriptionModifier != nil {
req.Payload, _ = opts.SessionDescriptionModifier(&sessionDescription)
} else {
req.Payload, _ = json.Marshal(sessionDescription)
}
if err = conn.WriteJSON(req); err != nil { if err = conn.WriteJSON(req); err != nil {
return nil, err return nil, err
} }
@@ -234,5 +231,5 @@ func wyzeClient(rawURL string) (core.Producer, error) {
"ice_servers": []string{string(kvs.Servers)}, "ice_servers": []string{string(kvs.Servers)},
} }
return kinesisClient(kvs.URL, query, "webrtc/wyze", &kinesisClientOpts{}) return kinesisClient(kvs.URL, query, "webrtc/wyze", nil)
} }

View File

@@ -1,62 +1,40 @@
package webrtc package webrtc
import ( import (
"encoding/json"
"net/url" "net/url"
"strings"
"github.com/AlexxIT/go2rtc/pkg/core" "github.com/AlexxIT/go2rtc/pkg/core"
pion "github.com/pion/webrtc/v3" "github.com/AlexxIT/go2rtc/pkg/webrtc"
) )
// SessionDescription is used to expose local and remote session descriptions.
type SwitchBotSessionDescription struct {
Type string `json:"type"`
SDP string `json:"sdp"`
Resolution SwitchBotResolution `json:"resolution"`
PlayType int `json:"play_type"`
}
func switchbotClient(rawURL string, query url.Values) (core.Producer, error) { func switchbotClient(rawURL string, query url.Values) (core.Producer, error) {
return kinesisClient(rawURL, query, "webrtc/switchbot", &kinesisClientOpts{ return kinesisClient(rawURL, query, "webrtc/switchbot", func(prod *webrtc.Conn, query url.Values) (any, error) {
SessionDescriptionModifier: func(sd *pion.SessionDescription) ([]byte, error) { medias := []*core.Media{
resolution, ok := parseSwitchBotResolution(query.Get("resolution")) {Kind: core.KindVideo, Direction: core.DirectionRecvonly},
if !ok { }
resolution = SwitchBotResolutionSD
} offer, err := prod.CreateOffer(medias)
json, err := json.Marshal(SwitchBotSessionDescription{ if err != nil {
Type: sd.Type.String(), return nil, err
SDP: sd.SDP, }
Resolution: resolution,
PlayType: 0, v := struct {
}) Type string `json:"type"`
return json, err SDP string `json:"sdp"`
}, Resolution int `json:"resolution"`
MediaModifier: func() ([]*core.Media, error) { PlayType int `json:"play_type"`
return []*core.Media{ }{
{Kind: core.KindVideo, Direction: core.DirectionRecvonly}, Type: "offer",
//{Kind: core.KindAudio, Direction: core.DirectionRecvonly}, SDP: offer,
//{Kind: core.KindAudio, Direction: core.DirectionSendRecv}, }
//{Kind: "Data", Direction: core.DirectionSendRecv},
}, nil switch query.Get("resolution") {
}, case "hd":
v.Resolution = 0
case "sd":
v.Resolution = 1
}
return v, nil
}) })
} }
type SwitchBotResolution int
const (
SwitchBotResolutionHD SwitchBotResolution = 0
SwitchBotResolutionSD = 1
)
func parseSwitchBotResolution(str string) (SwitchBotResolution, bool) {
var (
resolutionMap = map[string]SwitchBotResolution{
"hd": SwitchBotResolutionHD,
"sd": SwitchBotResolutionSD,
}
)
c, ok := resolutionMap[strings.ToLower(str)]
return c, ok
}