add rtsp support

This commit is contained in:
seydx
2025-05-11 01:21:20 +02:00
parent 30d48e139c
commit 6e35f1a389
3 changed files with 64 additions and 11 deletions
+51 -7
View File
@@ -20,6 +20,7 @@ type TuyaClient struct {
httpClient *http.Client
mqtt *TuyaMQTT
apiURL string
rtspURL string
sessionID string
clientID string
deviceID string
@@ -41,6 +42,17 @@ type Token struct {
ExpireTime int64 `json:"expire_time"`
}
type RTSPRequest struct {
Type string `json:"type"`
}
type RTSPResponse struct {
Success bool `json:"success"`
Result struct {
URL string `json:"url"`
} `json:"result"`
}
type AudioAttributes struct {
CallMode []int `json:"call_mode"` // 1 = one way, 2 = two way
HardwareCapability []int `json:"hardware_capability"` // 1 = mic, 2 = speaker
@@ -133,7 +145,7 @@ const (
defaultTimeout = 5 * time.Second
)
func NewTuyaClient(openAPIURL string, deviceID string, uid string, clientID string, secret string) (*TuyaClient, error) {
func NewTuyaClient(openAPIURL string, deviceID string, uid string, clientID string, secret string, useRTSP bool) (*TuyaClient, error) {
client := &TuyaClient{
httpClient: &http.Client{Timeout: defaultTimeout},
mqtt: &TuyaMQTT{waiter: core.Waiter{}},
@@ -149,12 +161,18 @@ func NewTuyaClient(openAPIURL string, deviceID string, uid string, clientID stri
return nil, fmt.Errorf("failed to initialize token: %w", err)
}
if err := client.InitDevice(); err != nil {
return nil, fmt.Errorf("failed to initialize device: %w", err)
}
if useRTSP {
if err := client.GetRTSP(); err != nil {
return nil, fmt.Errorf("failed to get RTSP URL: %w", err)
}
} else {
if err := client.InitDevice(); err != nil {
return nil, fmt.Errorf("failed to initialize device: %w", err)
}
if err := client.StartMQTT(); err != nil {
return nil, fmt.Errorf("failed to start MQTT: %w", err)
if err := client.StartMQTT(); err != nil {
return nil, fmt.Errorf("failed to start MQTT: %w", err)
}
}
return client, nil
@@ -324,6 +342,32 @@ func(c *TuyaClient) InitDevice() (err error) {
return nil
}
func(c *TuyaClient) GetRTSP() (err error) {
url := fmt.Sprintf("https://%s/v1.0/devices/%s/stream/actions/allocate", c.apiURL, c.deviceID)
request := &RTSPRequest{
Type: "rtsp",
}
body, err := c.Request("POST", url, request)
if err != nil {
return fmt.Errorf("failed to get rtsp url: %w", err)
}
var rtspResponse RTSPResponse
err = json.Unmarshal(body, &rtspResponse)
if err != nil {
return fmt.Errorf("failed to unmarshal rtsp response: %w", err)
}
if !rtspResponse.Success {
return fmt.Errorf("failed to get rtsp url: %s", string(body))
}
c.rtspURL = rtspResponse.Result.URL
return nil
}
func(c *TuyaClient) LoadHubConfig() (config *OpenIoTHubConfig, err error) {
url := fmt.Sprintf("https://%s/v2.0/open-iot-hub/access/config", c.apiURL)
@@ -335,12 +379,12 @@ func(c *TuyaClient) LoadHubConfig() (config *OpenIoTHubConfig, err error) {
Topics: "ipc",
}
var openIoTHubConfigResponse OpenIoTHubConfigResponse
body, err := c.Request("POST", url, request)
if err != nil {
return nil, fmt.Errorf("failed to get OpenIoTHub config: %w", err)
}
var openIoTHubConfigResponse OpenIoTHubConfigResponse
err = json.Unmarshal(body, &openIoTHubConfigResponse)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal OpenIoTHub config response: %w", err)
+12 -2
View File
@@ -7,6 +7,7 @@ import (
"net/url"
"strconv"
"github.com/AlexxIT/go2rtc/internal/streams"
"github.com/AlexxIT/go2rtc/pkg/core"
"github.com/AlexxIT/go2rtc/pkg/webrtc"
pion "github.com/pion/webrtc/v4"
@@ -27,7 +28,7 @@ const (
DefaultInURL = "openapi.tuyain.com"
)
func Dial(rawURL string) (*Client, error) {
func Dial(rawURL string) (core.Producer, error) {
// Parse URL and validate basic params
u, err := url.Parse(rawURL)
if err != nil {
@@ -40,13 +41,14 @@ func Dial(rawURL string) (*Client, error) {
clientID := query.Get("client_id")
secret := query.Get("secret")
resolution := query.Get("resolution")
useRTSP := query.Get("use_rtsp") == "1"
if deviceID == "" || uid == "" || clientID == "" || secret == "" {
return nil, errors.New("tuya: wrong query")
}
// Initialize Tuya API client
tuyaAPI, err := NewTuyaClient(u.Hostname(), deviceID, uid, clientID, secret)
tuyaAPI, err := NewTuyaClient(u.Hostname(), deviceID, uid, clientID, secret, useRTSP)
if err != nil {
return nil, err
}
@@ -56,6 +58,14 @@ func Dial(rawURL string) (*Client, error) {
done: make(chan struct{}),
}
if useRTSP {
if client.api.rtspURL == "" {
return nil, errors.New("tuya: no rtsp url")
}
return streams.GetProducer(client.api.rtspURL)
}
conf := pion.Configuration{
ICEServers: client.api.iceServers,
ICETransportPolicy: pion.ICETransportPolicyAll,
+1 -2
View File
@@ -107,9 +107,8 @@ func(c *TuyaClient) StartMQTT() error {
}
func(c *TuyaClient) StopMQTT() {
c.sendDisconnect()
if c.mqtt.client != nil {
c.sendDisconnect()
c.mqtt.client.Disconnect(1000)
}
}