add rtsp support
This commit is contained in:
+51
-7
@@ -20,6 +20,7 @@ type TuyaClient struct {
|
|||||||
httpClient *http.Client
|
httpClient *http.Client
|
||||||
mqtt *TuyaMQTT
|
mqtt *TuyaMQTT
|
||||||
apiURL string
|
apiURL string
|
||||||
|
rtspURL string
|
||||||
sessionID string
|
sessionID string
|
||||||
clientID string
|
clientID string
|
||||||
deviceID string
|
deviceID string
|
||||||
@@ -41,6 +42,17 @@ type Token struct {
|
|||||||
ExpireTime int64 `json:"expire_time"`
|
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 {
|
type AudioAttributes struct {
|
||||||
CallMode []int `json:"call_mode"` // 1 = one way, 2 = two way
|
CallMode []int `json:"call_mode"` // 1 = one way, 2 = two way
|
||||||
HardwareCapability []int `json:"hardware_capability"` // 1 = mic, 2 = speaker
|
HardwareCapability []int `json:"hardware_capability"` // 1 = mic, 2 = speaker
|
||||||
@@ -133,7 +145,7 @@ const (
|
|||||||
defaultTimeout = 5 * time.Second
|
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{
|
client := &TuyaClient{
|
||||||
httpClient: &http.Client{Timeout: defaultTimeout},
|
httpClient: &http.Client{Timeout: defaultTimeout},
|
||||||
mqtt: &TuyaMQTT{waiter: core.Waiter{}},
|
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)
|
return nil, fmt.Errorf("failed to initialize token: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := client.InitDevice(); err != nil {
|
if useRTSP {
|
||||||
return nil, fmt.Errorf("failed to initialize device: %w", err)
|
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 {
|
if err := client.StartMQTT(); err != nil {
|
||||||
return nil, fmt.Errorf("failed to start MQTT: %w", err)
|
return nil, fmt.Errorf("failed to start MQTT: %w", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return client, nil
|
return client, nil
|
||||||
@@ -324,6 +342,32 @@ func(c *TuyaClient) InitDevice() (err error) {
|
|||||||
return nil
|
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) {
|
func(c *TuyaClient) LoadHubConfig() (config *OpenIoTHubConfig, err error) {
|
||||||
url := fmt.Sprintf("https://%s/v2.0/open-iot-hub/access/config", c.apiURL)
|
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",
|
Topics: "ipc",
|
||||||
}
|
}
|
||||||
|
|
||||||
var openIoTHubConfigResponse OpenIoTHubConfigResponse
|
|
||||||
body, err := c.Request("POST", url, request)
|
body, err := c.Request("POST", url, request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to get OpenIoTHub config: %w", err)
|
return nil, fmt.Errorf("failed to get OpenIoTHub config: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var openIoTHubConfigResponse OpenIoTHubConfigResponse
|
||||||
err = json.Unmarshal(body, &openIoTHubConfigResponse)
|
err = json.Unmarshal(body, &openIoTHubConfigResponse)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to unmarshal OpenIoTHub config response: %w", err)
|
return nil, fmt.Errorf("failed to unmarshal OpenIoTHub config response: %w", err)
|
||||||
|
|||||||
+12
-2
@@ -7,6 +7,7 @@ import (
|
|||||||
"net/url"
|
"net/url"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/AlexxIT/go2rtc/internal/streams"
|
||||||
"github.com/AlexxIT/go2rtc/pkg/core"
|
"github.com/AlexxIT/go2rtc/pkg/core"
|
||||||
"github.com/AlexxIT/go2rtc/pkg/webrtc"
|
"github.com/AlexxIT/go2rtc/pkg/webrtc"
|
||||||
pion "github.com/pion/webrtc/v4"
|
pion "github.com/pion/webrtc/v4"
|
||||||
@@ -27,7 +28,7 @@ const (
|
|||||||
DefaultInURL = "openapi.tuyain.com"
|
DefaultInURL = "openapi.tuyain.com"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Dial(rawURL string) (*Client, error) {
|
func Dial(rawURL string) (core.Producer, error) {
|
||||||
// Parse URL and validate basic params
|
// Parse URL and validate basic params
|
||||||
u, err := url.Parse(rawURL)
|
u, err := url.Parse(rawURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -40,13 +41,14 @@ func Dial(rawURL string) (*Client, error) {
|
|||||||
clientID := query.Get("client_id")
|
clientID := query.Get("client_id")
|
||||||
secret := query.Get("secret")
|
secret := query.Get("secret")
|
||||||
resolution := query.Get("resolution")
|
resolution := query.Get("resolution")
|
||||||
|
useRTSP := query.Get("use_rtsp") == "1"
|
||||||
|
|
||||||
if deviceID == "" || uid == "" || clientID == "" || secret == "" {
|
if deviceID == "" || uid == "" || clientID == "" || secret == "" {
|
||||||
return nil, errors.New("tuya: wrong query")
|
return nil, errors.New("tuya: wrong query")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize Tuya API client
|
// 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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -56,6 +58,14 @@ func Dial(rawURL string) (*Client, error) {
|
|||||||
done: make(chan struct{}),
|
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{
|
conf := pion.Configuration{
|
||||||
ICEServers: client.api.iceServers,
|
ICEServers: client.api.iceServers,
|
||||||
ICETransportPolicy: pion.ICETransportPolicyAll,
|
ICETransportPolicy: pion.ICETransportPolicyAll,
|
||||||
|
|||||||
+1
-2
@@ -107,9 +107,8 @@ func(c *TuyaClient) StartMQTT() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func(c *TuyaClient) StopMQTT() {
|
func(c *TuyaClient) StopMQTT() {
|
||||||
c.sendDisconnect()
|
|
||||||
|
|
||||||
if c.mqtt.client != nil {
|
if c.mqtt.client != nil {
|
||||||
|
c.sendDisconnect()
|
||||||
c.mqtt.client.Disconnect(1000)
|
c.mqtt.client.Disconnect(1000)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user