This commit is contained in:
seydx
2025-05-12 22:55:55 +02:00
parent 05c12b34e5
commit 6d8d6a91ef
6 changed files with 300 additions and 300 deletions
+1 -1
View File
@@ -89,7 +89,7 @@ func main() {
roborock.Init() // roborock source
homekit.Init() // homekit source
ring.Init() // ring source
tuya.Init() // tuya source
tuya.Init() // tuya source
nest.Init() // nest source
bubble.Init() // bubble source
expr.Init() // expr source
+1 -1
View File
@@ -62,7 +62,7 @@ func ServiceCameraRTPStreamManagement() *hap.Service {
VideoAttrs: []VideoAttrs{
{Width: 1920, Height: 1080, Framerate: 30},
{Width: 1280, Height: 720, Framerate: 30}, // important for iPhones
{Width: 320, Height: 240, Framerate: 15}, // apple watch
{Width: 320, Height: 240, Framerate: 15}, // apple watch
},
},
},
+1 -1
View File
@@ -292,7 +292,7 @@ func dial(req *http.Request, brand, username, password string) (net.Conn, *http.
return nil, nil, err
}
_, _ = io.Copy(io.Discard, res.Body) // discard leftovers
_ = res.Body.Close() // ignore response body
_ = res.Body.Close() // ignore response body
auth := res.Header.Get("WWW-Authenticate")
+235 -235
View File
@@ -17,146 +17,146 @@ import (
)
type TuyaClient struct {
httpClient *http.Client
mqtt *TuyaMQTT
apiURL string
rtspURL string
hlsURL string
sessionId string
clientId string
clientSecret string
deviceId string
accessToken string
refreshToken string
expireTime int64
uid string
motoId string
auth string
skill *Skill
iceServers []pionWebrtc.ICEServer
medias []*core.Media
hasBackchannel bool
httpClient *http.Client
mqtt *TuyaMQTT
apiURL string
rtspURL string
hlsURL string
sessionId string
clientId string
clientSecret string
deviceId string
accessToken string
refreshToken string
expireTime int64
uid string
motoId string
auth string
skill *Skill
iceServers []pionWebrtc.ICEServer
medias []*core.Media
hasBackchannel bool
}
type Token struct {
UID string `json:"uid"`
AccessToken string `json:"access_token"`
RefreshToken string `json:"refresh_token"`
ExpireTime int64 `json:"expire_time"`
UID string `json:"uid"`
AccessToken string `json:"access_token"`
RefreshToken string `json:"refresh_token"`
ExpireTime int64 `json:"expire_time"`
}
type AudioAttributes struct {
CallMode []int `json:"call_mode"` // 1 = one way, 2 = two way
HardwareCapability []int `json:"hardware_capability"` // 1 = mic, 2 = speaker
CallMode []int `json:"call_mode"` // 1 = one way, 2 = two way
HardwareCapability []int `json:"hardware_capability"` // 1 = mic, 2 = speaker
}
type OpenApiICE struct {
Urls string `json:"urls"`
Username string `json:"username"`
Credential string `json:"credential"`
TTL int `json:"ttl"`
Urls string `json:"urls"`
Username string `json:"username"`
Credential string `json:"credential"`
TTL int `json:"ttl"`
}
type WebICE struct {
Urls string `json:"urls"`
Username string `json:"username,omitempty"`
Credential string `json:"credential,omitempty"`
Urls string `json:"urls"`
Username string `json:"username,omitempty"`
Credential string `json:"credential,omitempty"`
}
type P2PConfig struct {
Ices []OpenApiICE `json:"ices"`
Ices []OpenApiICE `json:"ices"`
}
type Skill struct {
WebRTC int `json:"webrtc"`
WebRTC int `json:"webrtc"`
Audios []struct {
Channels int `json:"channels"`
DataBit int `json:"dataBit"`
CodecType int `json:"codecType"`
SampleRate int `json:"sampleRate"`
Channels int `json:"channels"`
DataBit int `json:"dataBit"`
CodecType int `json:"codecType"`
SampleRate int `json:"sampleRate"`
} `json:"audios"`
Videos []struct {
StreamType int `json:"streamType"` // streamType = 2 => main stream - streamType = 4 => sub stream
ProfileId string `json:"profileId"`
Width int `json:"width"`
CodecType int `json:"codecType"`
SampleRate int `json:"sampleRate"`
Height int `json:"height"`
StreamType int `json:"streamType"` // streamType = 2 => main stream - streamType = 4 => sub stream
ProfileId string `json:"profileId"`
Width int `json:"width"`
CodecType int `json:"codecType"`
SampleRate int `json:"sampleRate"`
Height int `json:"height"`
} `json:"videos"`
}
type WebRTConfig struct {
AudioAttributes AudioAttributes `json:"audio_attributes"`
Auth string `json:"auth"`
ID string `json:"id"`
MotoID string `json:"moto_id"`
P2PConfig P2PConfig `json:"p2p_config"`
ProtocolVersion string `json:"protocol_version"`
Skill string `json:"skill"`
SupportsWebRTCRecord bool `json:"supports_webrtc_record"`
SupportsWebRTC bool `json:"supports_webrtc"`
VedioClaritiy int `json:"vedio_clarity"`
VideoClaritiy int `json:"video_clarity"`
VideoClarities []int `json:"video_clarities"`
AudioAttributes AudioAttributes `json:"audio_attributes"`
Auth string `json:"auth"`
ID string `json:"id"`
MotoID string `json:"moto_id"`
P2PConfig P2PConfig `json:"p2p_config"`
ProtocolVersion string `json:"protocol_version"`
Skill string `json:"skill"`
SupportsWebRTCRecord bool `json:"supports_webrtc_record"`
SupportsWebRTC bool `json:"supports_webrtc"`
VedioClaritiy int `json:"vedio_clarity"`
VideoClaritiy int `json:"video_clarity"`
VideoClarities []int `json:"video_clarities"`
}
type OpenIoTHubConfig struct {
Url string `json:"url"`
ClientID string `json:"client_id"`
Username string `json:"username"`
Password string `json:"password"`
Url string `json:"url"`
ClientID string `json:"client_id"`
Username string `json:"username"`
Password string `json:"password"`
SinkTopic struct {
IPC string `json:"ipc"`
} `json:"sink_topic"`
SourceSink struct {
IPC string `json:"ipc"`
} `json:"source_topic"`
ExpireTime int `json:"expire_time"`
ExpireTime int `json:"expire_time"`
}
type WebRTCConfigResponse struct {
Success bool `json:"success"`
Result WebRTConfig `json:"result"`
Msg string `json:"msg,omitempty"`
Code int `json:"code,omitempty"`
Success bool `json:"success"`
Result WebRTConfig `json:"result"`
Msg string `json:"msg,omitempty"`
Code int `json:"code,omitempty"`
}
type TokenResponse struct {
Success bool `json:"success"`
Result Token `json:"result"`
Msg string `json:"msg,omitempty"`
Code int `json:"code,omitempty"`
Success bool `json:"success"`
Result Token `json:"result"`
Msg string `json:"msg,omitempty"`
Code int `json:"code,omitempty"`
}
type AllocateRequest struct {
Type string `json:"type"`
Type string `json:"type"`
}
type AllocateResponse struct {
Success bool `json:"success"`
Success bool `json:"success"`
Result struct {
URL string `json:"url"`
} `json:"result"`
Msg string `json:"msg,omitempty"`
Code int `json:"code,omitempty"`
Msg string `json:"msg,omitempty"`
Code int `json:"code,omitempty"`
}
type OpenIoTHubConfigRequest struct {
UID string `json:"uid"`
UniqueID string `json:"unique_id"`
LinkType string `json:"link_type"`
Topics string `json:"topics"`
UID string `json:"uid"`
UniqueID string `json:"unique_id"`
LinkType string `json:"link_type"`
Topics string `json:"topics"`
}
type OpenIoTHubConfigResponse struct {
Success bool `json:"success"`
Result OpenIoTHubConfig `json:"result"`
Msg string `json:"msg,omitempty"`
Code int `json:"code,omitempty"`
Success bool `json:"success"`
Result OpenIoTHubConfig `json:"result"`
Msg string `json:"msg,omitempty"`
Code int `json:"code,omitempty"`
}
const (
defaultTimeout = 5 * time.Second
defaultTimeout = 5 * time.Second
)
func NewTuyaClient(openAPIURL string, deviceId string, uid string, clientId string, clientSecret string, streamMode string) (*TuyaClient, error) {
@@ -164,7 +164,7 @@ func NewTuyaClient(openAPIURL string, deviceId string, uid string, clientId stri
httpClient: &http.Client{Timeout: defaultTimeout},
mqtt: &TuyaMQTT{waiter: core.Waiter{}},
apiURL: openAPIURL,
sessionId: core.RandString(6, 62),
sessionId: core.RandString(6, 62),
clientId: clientId,
deviceId: deviceId,
clientSecret: clientSecret,
@@ -202,7 +202,7 @@ func (c *TuyaClient) Close() {
c.httpClient.CloseIdleConnections()
}
func(c *TuyaClient) Request(method string, url string, body any) ([]byte, error) {
func (c *TuyaClient) Request(method string, url string, body any) ([]byte, error) {
var bodyReader io.Reader
if body != nil {
jsonBody, err := json.Marshal(body)
@@ -249,7 +249,7 @@ func(c *TuyaClient) Request(method string, url string, body any) ([]byte, error)
return res, nil
}
func(c *TuyaClient) InitToken() (err error) {
func (c *TuyaClient) InitToken() (err error) {
url := fmt.Sprintf("https://%s/v1.0/token?grant_type=1", c.apiURL)
c.accessToken = ""
@@ -259,7 +259,7 @@ func(c *TuyaClient) InitToken() (err error) {
if err != nil {
return err
}
var tokenResponse TokenResponse
err = json.Unmarshal(body, &tokenResponse)
if err != nil {
@@ -277,139 +277,139 @@ func(c *TuyaClient) InitToken() (err error) {
return nil
}
func(c *TuyaClient) InitDevice() (err error) {
url := fmt.Sprintf("https://%s/v1.0/users/%s/devices/%s/webrtc-configs", c.apiURL, c.uid, c.deviceId)
func (c *TuyaClient) InitDevice() (err error) {
url := fmt.Sprintf("https://%s/v1.0/users/%s/devices/%s/webrtc-configs", c.apiURL, c.uid, c.deviceId)
body, err := c.Request("GET", url, nil)
if err != nil {
return err
}
body, err := c.Request("GET", url, nil)
if err != nil {
return err
}
var webRTCConfigResponse WebRTCConfigResponse
err = json.Unmarshal(body, &webRTCConfigResponse)
if err != nil {
return err
}
var webRTCConfigResponse WebRTCConfigResponse
err = json.Unmarshal(body, &webRTCConfigResponse)
if err != nil {
return err
}
if !webRTCConfigResponse.Success {
return fmt.Errorf("error: %s", webRTCConfigResponse.Msg)
}
c.motoId = webRTCConfigResponse.Result.MotoID
c.auth = webRTCConfigResponse.Result.Auth
c.auth = webRTCConfigResponse.Result.Auth
c.skill = &Skill{
Audios: []struct {
Channels int `json:"channels"`
DataBit int `json:"dataBit"`
CodecType int `json:"codecType"`
SampleRate int `json:"sampleRate"`
}{},
Videos: []struct {
StreamType int `json:"streamType"`
ProfileId string `json:"profileId"`
Width int `json:"width"`
CodecType int `json:"codecType"`
SampleRate int `json:"sampleRate"`
Height int `json:"height"`
}{},
}
c.skill = &Skill{
Audios: []struct {
Channels int `json:"channels"`
DataBit int `json:"dataBit"`
CodecType int `json:"codecType"`
SampleRate int `json:"sampleRate"`
}{},
Videos: []struct {
StreamType int `json:"streamType"`
ProfileId string `json:"profileId"`
Width int `json:"width"`
CodecType int `json:"codecType"`
SampleRate int `json:"sampleRate"`
Height int `json:"height"`
}{},
}
if webRTCConfigResponse.Result.Skill != "" {
_ = json.Unmarshal([]byte(webRTCConfigResponse.Result.Skill), c.skill)
}
if webRTCConfigResponse.Result.Skill != "" {
_ = json.Unmarshal([]byte(webRTCConfigResponse.Result.Skill), c.skill)
}
var audioDirection string
if contains(webRTCConfigResponse.Result.AudioAttributes.CallMode, 2) &&
contains(webRTCConfigResponse.Result.AudioAttributes.HardwareCapability, 1) {
audioDirection = core.DirectionSendRecv
var audioDirection string
if contains(webRTCConfigResponse.Result.AudioAttributes.CallMode, 2) &&
contains(webRTCConfigResponse.Result.AudioAttributes.HardwareCapability, 1) {
audioDirection = core.DirectionSendRecv
c.hasBackchannel = true
} else {
audioDirection = core.DirectionRecvonly
} else {
audioDirection = core.DirectionRecvonly
c.hasBackchannel = false
}
c.medias = make([]*core.Media, 0)
if len(c.skill.Audios) > 0 {
// Use the first Audio-Codec
audio := c.skill.Audios[0]
}
c.medias = append(c.medias, &core.Media{
Kind: core.KindAudio,
Direction: audioDirection,
Codecs: []*core.Codec{
{
Name: "PCMU",
ClockRate: uint32(audio.SampleRate),
Channels: uint8(audio.Channels),
},
},
})
} else {
// Use default values for Audio
c.medias = append(c.medias, &core.Media{
Kind: core.KindAudio,
Direction: core.DirectionRecvonly,
Codecs: []*core.Codec{
{
Name: "PCMU",
ClockRate: uint32(8000),
Channels: uint8(1),
},
},
})
}
c.medias = make([]*core.Media, 0)
if len(c.skill.Videos) > 0 {
// Use the first Video-Codec
video := c.skill.Videos[0]
if len(c.skill.Audios) > 0 {
// Use the first Audio-Codec
audio := c.skill.Audios[0]
c.medias = append(c.medias, &core.Media{
Kind: core.KindVideo,
Direction: core.DirectionRecvonly,
Codecs: []*core.Codec{
{
Name: core.CodecH265,
ClockRate: uint32(video.SampleRate),
PayloadType: 96,
},
c.medias = append(c.medias, &core.Media{
Kind: core.KindAudio,
Direction: audioDirection,
Codecs: []*core.Codec{
{
Name: core.CodecH264,
ClockRate: uint32(video.SampleRate),
PayloadType: 96,
},
},
})
} else {
// Use default values for Video
c.medias = append(c.medias, &core.Media{
Kind: core.KindVideo,
Direction: core.DirectionRecvonly,
Codecs: []*core.Codec{
{
Name: core.CodecH264,
ClockRate: uint32(90000),
PayloadType: 96,
},
},
})
}
Name: "PCMU",
ClockRate: uint32(audio.SampleRate),
Channels: uint8(audio.Channels),
},
},
})
} else {
// Use default values for Audio
c.medias = append(c.medias, &core.Media{
Kind: core.KindAudio,
Direction: core.DirectionRecvonly,
Codecs: []*core.Codec{
{
Name: "PCMU",
ClockRate: uint32(8000),
Channels: uint8(1),
},
},
})
}
iceServersBytes, err := json.Marshal(&webRTCConfigResponse.Result.P2PConfig.Ices)
if err != nil {
return err
}
if len(c.skill.Videos) > 0 {
// Use the first Video-Codec
video := c.skill.Videos[0]
c.iceServers, err = webrtc.UnmarshalICEServers([]byte(iceServersBytes))
if err != nil {
return err
}
c.medias = append(c.medias, &core.Media{
Kind: core.KindVideo,
Direction: core.DirectionRecvonly,
Codecs: []*core.Codec{
{
Name: core.CodecH265,
ClockRate: uint32(video.SampleRate),
PayloadType: 96,
},
{
Name: core.CodecH264,
ClockRate: uint32(video.SampleRate),
PayloadType: 96,
},
},
})
} else {
// Use default values for Video
c.medias = append(c.medias, &core.Media{
Kind: core.KindVideo,
Direction: core.DirectionRecvonly,
Codecs: []*core.Codec{
{
Name: core.CodecH264,
ClockRate: uint32(90000),
PayloadType: 96,
},
},
})
}
return nil
iceServersBytes, err := json.Marshal(&webRTCConfigResponse.Result.P2PConfig.Ices)
if err != nil {
return err
}
c.iceServers, err = webrtc.UnmarshalICEServers([]byte(iceServersBytes))
if err != nil {
return err
}
return nil
}
func(c *TuyaClient) GetStreamUrl(streamType string) (err error) {
func (c *TuyaClient) GetStreamUrl(streamType string) (err error) {
url := fmt.Sprintf("https://%s/v1.0/devices/%s/stream/actions/allocate", c.apiURL, c.deviceId)
request := &AllocateRequest{
@@ -443,7 +443,7 @@ func(c *TuyaClient) GetStreamUrl(streamType string) (err error) {
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)
request := &OpenIoTHubConfigRequest{
@@ -467,53 +467,53 @@ func(c *TuyaClient) LoadHubConfig() (config *OpenIoTHubConfig, err error) {
if !openIoTHubConfigResponse.Success {
return nil, fmt.Errorf("error: %s", openIoTHubConfigResponse.Msg)
}
return &openIoTHubConfigResponse.Result, nil
}
// Search the streamType based on the selection "main" or "sub"
func (c *TuyaClient) getStreamType(streamChoice string) uint32 {
// Default streamType if nothing is found
defaultStreamType := uint32(1)
defaultStreamType := uint32(1)
if c.skill == nil || len(c.skill.Videos) == 0 {
return defaultStreamType
}
if c.skill == nil || len(c.skill.Videos) == 0 {
return defaultStreamType
}
// Find the highest and lowest resolution
var highestResType uint32 = defaultStreamType
var highestRes int = 0
var lowestResType uint32 = defaultStreamType
var lowestRes int = 0
for _, video := range c.skill.Videos {
res := video.Width * video.Height
// Highest Resolution
if res > highestRes {
highestRes = res
highestResType = uint32(video.StreamType)
}
var highestResType uint32 = defaultStreamType
var highestRes int = 0
var lowestResType uint32 = defaultStreamType
var lowestRes int = 0
for _, video := range c.skill.Videos {
res := video.Width * video.Height
// Highest Resolution
if res > highestRes {
highestRes = res
highestResType = uint32(video.StreamType)
}
// Lower Resolution (or first if not set yet)
if lowestRes == 0 || res < lowestRes {
lowestRes = res
lowestResType = uint32(video.StreamType)
}
}
// Return the streamType based on the selection
switch streamChoice {
case "main":
return highestResType
case "sub":
return lowestResType
default:
return defaultStreamType
}
if lowestRes == 0 || res < lowestRes {
lowestRes = res
lowestResType = uint32(video.StreamType)
}
}
// Return the streamType based on the selection
switch streamChoice {
case "main":
return highestResType
case "sub":
return lowestResType
default:
return defaultStreamType
}
}
func(c *TuyaClient) calBusinessSign(ts int64) string {
func (c *TuyaClient) calBusinessSign(ts int64) string {
data := fmt.Sprintf("%s%s%s%d", c.clientId, c.accessToken, c.clientSecret, ts)
val := md5.Sum([]byte(data))
res := fmt.Sprintf("%X", val)
@@ -527,4 +527,4 @@ func contains(slice []int, val int) bool {
}
}
return false
}
}
+13 -13
View File
@@ -14,18 +14,18 @@ import (
)
type Client struct {
api *TuyaClient
prod core.Producer
done chan struct{}
api *TuyaClient
prod core.Producer
done chan struct{}
}
const (
DefaultCnURL = "openapi.tuyacn.com"
DefaultWestUsURL = "openapi.tuyaus.com"
DefaultEastUsURL = "openapi-ueaz.tuyaus.com"
DefaultCnURL = "openapi.tuyacn.com"
DefaultWestUsURL = "openapi.tuyaus.com"
DefaultEastUsURL = "openapi-ueaz.tuyaus.com"
DefaultCentralEuURL = "openapi.tuyaeu.com"
DefaultWestEuURL = "openapi-weaz.tuyaeu.com"
DefaultInURL = "openapi.tuyain.com"
DefaultWestEuURL = "openapi-weaz.tuyaeu.com"
DefaultInURL = "openapi.tuyain.com"
)
func Dial(rawURL string) (core.Producer, error) {
@@ -77,7 +77,7 @@ func Dial(rawURL string) (core.Producer, error) {
}
client := &Client{
api: tuyaAPI,
api: tuyaAPI,
done: make(chan struct{}),
}
@@ -93,7 +93,7 @@ func Dial(rawURL string) (core.Producer, error) {
return streams.GetProducer(client.api.hlsURL)
} else {
conf := pion.Configuration{
ICEServers: client.api.iceServers,
ICEServers: client.api.iceServers,
ICETransportPolicy: pion.ICETransportPolicyAll,
BundlePolicy: pion.BundlePolicyMaxBundle,
}
@@ -138,12 +138,12 @@ func Dial(rawURL string) (core.Producer, error) {
client.Stop()
return
}
if err = prod.SetAnswer(answer.Sdp); err != nil {
client.Stop()
return
}
prod.SDP = answer.Sdp
}
@@ -159,7 +159,7 @@ func Dial(rawURL string) (core.Producer, error) {
client.api.mqtt.handleDisconnect = func() {
client.Stop()
}
client.api.mqtt.handleError = func(err error) {
// fmt.Printf("tuya: error: %s\n", err.Error())
client.Stop()
+49 -49
View File
@@ -11,67 +11,67 @@ import (
)
type TuyaMQTT struct {
client mqtt.Client
waiter core.Waiter
publishTopic string
subscribeTopic string
uid string
closed bool
handleAnswer func(answer AnswerFrame)
handleCandidate func(candidate CandidateFrame)
handleDisconnect func()
handleError func(err error)
client mqtt.Client
waiter core.Waiter
publishTopic string
subscribeTopic string
uid string
closed bool
handleAnswer func(answer AnswerFrame)
handleCandidate func(candidate CandidateFrame)
handleDisconnect func()
handleError func(err error)
}
type MqttFrameHeader struct {
Type string `json:"type"`
From string `json:"from"`
To string `json:"to"`
SubDevID string `json:"sub_dev_id"`
SessionID string `json:"sessionid"`
MotoID string `json:"moto_id"`
TransactionID string `json:"tid"`
Type string `json:"type"`
From string `json:"from"`
To string `json:"to"`
SubDevID string `json:"sub_dev_id"`
SessionID string `json:"sessionid"`
MotoID string `json:"moto_id"`
TransactionID string `json:"tid"`
}
type MqttFrame struct {
Header MqttFrameHeader `json:"header"`
Message json.RawMessage `json:"msg"`
Header MqttFrameHeader `json:"header"`
Message json.RawMessage `json:"msg"`
}
type OfferFrame struct {
Mode string `json:"mode"`
Sdp string `json:"sdp"`
StreamType uint32 `json:"stream_type"`
Auth string `json:"auth"`
Mode string `json:"mode"`
Sdp string `json:"sdp"`
StreamType uint32 `json:"stream_type"`
Auth string `json:"auth"`
}
type AnswerFrame struct {
Mode string `json:"mode"`
Sdp string `json:"sdp"`
Mode string `json:"mode"`
Sdp string `json:"sdp"`
}
type CandidateFrame struct {
Mode string `json:"mode"`
Candidate string `json:"candidate"`
Mode string `json:"mode"`
Candidate string `json:"candidate"`
}
type ResolutionFrame struct {
Mode string `json:"mode"`
Value int `json:"value"`
Mode string `json:"mode"`
Value int `json:"value"`
}
type DisconnectFrame struct {
Mode string `json:"mode"`
Mode string `json:"mode"`
}
type MqttMessage struct {
Protocol int `json:"protocol"`
Pv string `json:"pv"`
T int64 `json:"t"`
Data MqttFrame `json:"data"`
Protocol int `json:"protocol"`
Pv string `json:"pv"`
T int64 `json:"t"`
Data MqttFrame `json:"data"`
}
func(c *TuyaClient) StartMQTT() error {
func (c *TuyaClient) StartMQTT() error {
hubConfig, err := c.LoadHubConfig()
if err != nil {
return err
@@ -106,14 +106,14 @@ func(c *TuyaClient) StartMQTT() error {
return nil
}
func(c *TuyaClient) StopMQTT() {
func (c *TuyaClient) StopMQTT() {
if c.mqtt.client != nil {
c.sendDisconnect()
c.mqtt.client.Disconnect(1000)
}
}
func(c *TuyaClient) onConnect(client mqtt.Client) {
func (c *TuyaClient) onConnect(client mqtt.Client) {
if token := client.Subscribe(c.mqtt.subscribeTopic, 1, c.consume); token.Wait() && token.Error() != nil {
c.mqtt.waiter.Done(token.Error())
return
@@ -122,7 +122,7 @@ func(c *TuyaClient) onConnect(client mqtt.Client) {
c.mqtt.waiter.Done(nil)
}
func(c *TuyaClient) consume(client mqtt.Client, msg mqtt.Message) {
func (c *TuyaClient) consume(client mqtt.Client, msg mqtt.Message) {
var rmqtt MqttMessage
if err := json.Unmarshal(msg.Payload(), &rmqtt); err != nil {
c.mqtt.onError(fmt.Errorf("unmarshal mqtt message fail: %s, payload: %s", err.Error(), string(msg.Payload())))
@@ -143,7 +143,7 @@ func(c *TuyaClient) consume(client mqtt.Client, msg mqtt.Message) {
}
}
func(c *TuyaMQTT) onMqttAnswer(msg *MqttMessage) {
func (c *TuyaMQTT) onMqttAnswer(msg *MqttMessage) {
var answerFrame AnswerFrame
if err := json.Unmarshal(msg.Data.Message, &answerFrame); err != nil {
c.onError(fmt.Errorf("unmarshal mqtt answer frame fail: %s, session: %s, frame: %s",
@@ -152,11 +152,11 @@ func(c *TuyaMQTT) onMqttAnswer(msg *MqttMessage) {
string(msg.Data.Message)))
return
}
c.onAnswer(answerFrame)
}
func(c *TuyaMQTT) onMqttCandidate(msg *MqttMessage) {
func (c *TuyaMQTT) onMqttCandidate(msg *MqttMessage) {
var candidateFrame CandidateFrame
if err := json.Unmarshal(msg.Data.Message, &candidateFrame); err != nil {
c.onError(fmt.Errorf("unmarshal mqtt candidate frame fail: %s, session: %s, frame: %s",
@@ -173,30 +173,30 @@ func(c *TuyaMQTT) onMqttCandidate(msg *MqttMessage) {
c.onCandidate(candidateFrame)
}
func(c *TuyaMQTT) onMqttDisconnect() {
func (c *TuyaMQTT) onMqttDisconnect() {
c.closed = true
c.onDisconnect()
}
func(c *TuyaMQTT) onAnswer(answer AnswerFrame) {
func (c *TuyaMQTT) onAnswer(answer AnswerFrame) {
if c.handleAnswer != nil {
c.handleAnswer(answer)
}
}
func(c *TuyaMQTT) onCandidate(candidate CandidateFrame) {
func (c *TuyaMQTT) onCandidate(candidate CandidateFrame) {
if c.handleCandidate != nil {
c.handleCandidate(candidate)
}
}
func(c *TuyaMQTT) onDisconnect() {
func (c *TuyaMQTT) onDisconnect() {
if c.handleDisconnect != nil {
c.handleDisconnect()
}
}
func(c *TuyaMQTT) onError(err error) {
func (c *TuyaMQTT) onError(err error) {
if c.handleError != nil {
c.handleError(err)
}
@@ -220,12 +220,12 @@ func (c *TuyaClient) sendCandidate(candidate string) {
func (c *TuyaClient) sendResolution(resolution int) {
c.sendMqttMessage("resolution", 302, "", ResolutionFrame{
Mode: "webrtc",
Value: resolution,
Mode: "webrtc",
Value: resolution,
})
}
func(c *TuyaClient) sendDisconnect() {
func (c *TuyaClient) sendDisconnect() {
c.sendMqttMessage("disconnect", 302, "", DisconnectFrame{
Mode: "webrtc",
})