Add client for SwitchBot Camera WebRTC (supports special SessionDescription).

This commit is contained in:
hsakoh
2024-09-06 17:35:02 +09:00
parent 39c14e6556
commit 47b740ff35
4 changed files with 95 additions and 10 deletions
+3 -1
View File
@@ -41,9 +41,11 @@ func streamsHandler(rawURL string) (core.Producer, error) {
// https://aws.amazon.com/kinesis/video-streams/
// https://docs.aws.amazon.com/kinesisvideostreams-webrtc-dg/latest/devguide/what-is-kvswebrtc.html
// https://github.com/orgs/awslabs/repositories?q=kinesis+webrtc
return kinesisClient(rawURL, query, "webrtc/kinesis")
return kinesisClient(rawURL, query, "webrtc/kinesis", &kinesisClientOpts{})
} else if format == "openipc" {
return openIPCClient(rawURL, query)
} else if format == "switchbot" {
return switchbotClient(rawURL, query)
} else {
return go2rtcClient(rawURL)
}
+20 -4
View File
@@ -34,7 +34,12 @@ func (k kinesisResponse) String() string {
return fmt.Sprintf("type=%s, payload=%s", k.Type, k.Payload)
}
func kinesisClient(rawURL string, query url.Values, format string) (core.Producer, error) {
type kinesisClientOpts struct {
SessionDescriptionModifier func(*pion.SessionDescription) ([]byte, error)
MediaModifier func() ([]*core.Media, error)
}
func kinesisClient(rawURL string, query url.Values, format string, opts *kinesisClientOpts) (core.Producer, error) {
// 1. Connect to signalign server
conn, _, err := websocket.DefaultDialer.Dial(rawURL, nil)
if err != nil {
@@ -112,6 +117,12 @@ func kinesisClient(rawURL string, query url.Values, format string) (core.Produce
{Kind: core.KindVideo, Direction: core.DirectionRecvonly},
{Kind: core.KindAudio, Direction: core.DirectionRecvonly},
}
if opts.MediaModifier != nil {
medias, err = opts.MediaModifier()
if err != nil {
return nil, err
}
}
// 4. Create offer
offer, err := prod.CreateOffer(medias)
@@ -121,10 +132,15 @@ func kinesisClient(rawURL string, query url.Values, format string) (core.Produce
// 5. Send offer
req.Action = "SDP_OFFER"
req.Payload, _ = json.Marshal(pion.SessionDescription{
sessionDescription := pion.SessionDescription{
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 {
return nil, err
}
@@ -218,5 +234,5 @@ func wyzeClient(rawURL string) (core.Producer, error) {
"ice_servers": []string{string(kvs.Servers)},
}
return kinesisClient(kvs.URL, query, "webrtc/wyze")
return kinesisClient(kvs.URL, query, "webrtc/wyze", &kinesisClientOpts{})
}
+62
View File
@@ -0,0 +1,62 @@
package webrtc
import (
"encoding/json"
"net/url"
"strings"
"github.com/AlexxIT/go2rtc/pkg/core"
pion "github.com/pion/webrtc/v3"
)
// 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) {
return kinesisClient(rawURL, query, "webrtc/switchbot", &kinesisClientOpts{
SessionDescriptionModifier: func(sd *pion.SessionDescription) ([]byte, error) {
resolution, ok := parseSwitchBotResolution(query.Get("resolution"))
if !ok {
resolution = SwitchBotResolutionSD
}
json, err := json.Marshal(SwitchBotSessionDescription{
Type: sd.Type.String(),
SDP: sd.SDP,
Resolution: resolution,
PlayType: 0,
})
return json, err
},
MediaModifier: func() ([]*core.Media, error) {
return []*core.Media{
{Kind: core.KindVideo, Direction: core.DirectionRecvonly},
//{Kind: core.KindAudio, Direction: core.DirectionRecvonly},
//{Kind: core.KindAudio, Direction: core.DirectionSendRecv},
//{Kind: "Data", Direction: core.DirectionSendRecv},
}, 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
}