implement skill handling and media configuration
This commit is contained in:
+91
-6
@@ -31,6 +31,7 @@ type TuyaClient struct {
|
|||||||
motoID string
|
motoID string
|
||||||
auth string
|
auth string
|
||||||
iceServers []pionWebrtc.ICEServer
|
iceServers []pionWebrtc.ICEServer
|
||||||
|
medias []*core.Media
|
||||||
}
|
}
|
||||||
|
|
||||||
type Token struct {
|
type Token struct {
|
||||||
@@ -41,8 +42,8 @@ type Token struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type AudioAttributes struct {
|
type AudioAttributes struct {
|
||||||
CallMode []int `json:"call_mode"`
|
CallMode []int `json:"call_mode"` // 1 = one way, 2 = two way
|
||||||
HardwareCapability []int `json:"hardware_capability"`
|
HardwareCapability []int `json:"hardware_capability"` // 1 = mic, 2 = speaker
|
||||||
}
|
}
|
||||||
|
|
||||||
type OpenApiICE struct {
|
type OpenApiICE struct {
|
||||||
@@ -62,6 +63,24 @@ type P2PConfig struct {
|
|||||||
Ices []OpenApiICE `json:"ices"`
|
Ices []OpenApiICE `json:"ices"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Skill struct {
|
||||||
|
WebRTC int `json:"webrtc"`
|
||||||
|
Audios []struct {
|
||||||
|
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 => H265 and streamType = 4 => H264
|
||||||
|
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 {
|
type WebRTConfig struct {
|
||||||
AudioAttributes AudioAttributes `json:"audio_attributes"`
|
AudioAttributes AudioAttributes `json:"audio_attributes"`
|
||||||
Auth string `json:"auth"`
|
Auth string `json:"auth"`
|
||||||
@@ -73,14 +92,14 @@ type WebRTConfig struct {
|
|||||||
VideoClaritiy int `json:"video_clarity"`
|
VideoClaritiy int `json:"video_clarity"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type TokenResponse struct {
|
|
||||||
Result Token `json:"result"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type WebRTCConfigResponse struct {
|
type WebRTCConfigResponse struct {
|
||||||
Result WebRTConfig `json:"result"`
|
Result WebRTConfig `json:"result"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type TokenResponse struct {
|
||||||
|
Result Token `json:"result"`
|
||||||
|
}
|
||||||
|
|
||||||
type OpenIoTHubConfigRequest struct {
|
type OpenIoTHubConfigRequest struct {
|
||||||
UID string `json:"uid"`
|
UID string `json:"uid"`
|
||||||
UniqueID string `json:"unique_id"`
|
UniqueID string `json:"unique_id"`
|
||||||
@@ -234,6 +253,63 @@ func(c *TuyaClient) InitDevice() (err error) {
|
|||||||
c.motoID = webRTCConfigResponse.Result.MotoID
|
c.motoID = webRTCConfigResponse.Result.MotoID
|
||||||
c.auth = webRTCConfigResponse.Result.Auth
|
c.auth = webRTCConfigResponse.Result.Auth
|
||||||
|
|
||||||
|
var skill Skill
|
||||||
|
err = json.Unmarshal([]byte(webRTCConfigResponse.Result.Skill), &skill)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to unmarshal skill: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var audioDirection string
|
||||||
|
if contains(webRTCConfigResponse.Result.AudioAttributes.CallMode, 2) && contains(webRTCConfigResponse.Result.AudioAttributes.HardwareCapability, 1) {
|
||||||
|
audioDirection = core.DirectionSendRecv
|
||||||
|
} else {
|
||||||
|
audioDirection = core.DirectionRecvonly
|
||||||
|
}
|
||||||
|
|
||||||
|
c.medias = make([]*core.Media, 0)
|
||||||
|
for _, audio := range skill.Audios {
|
||||||
|
media := &core.Media{
|
||||||
|
Kind: core.KindAudio,
|
||||||
|
Direction: audioDirection,
|
||||||
|
Codecs: []*core.Codec{
|
||||||
|
{
|
||||||
|
Name: "PCMU",
|
||||||
|
ClockRate: uint32(audio.SampleRate),
|
||||||
|
Channels: uint8(audio.Channels),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
c.medias = append(c.medias, media)
|
||||||
|
}
|
||||||
|
|
||||||
|
// take only the first video codec
|
||||||
|
video := skill.Videos[0]
|
||||||
|
|
||||||
|
var name string
|
||||||
|
switch video.CodecType {
|
||||||
|
case 4:
|
||||||
|
name = core.CodecH265
|
||||||
|
case 2:
|
||||||
|
name = core.CodecH264
|
||||||
|
default:
|
||||||
|
name = core.CodecH264
|
||||||
|
}
|
||||||
|
|
||||||
|
media := &core.Media{
|
||||||
|
Kind: core.KindVideo,
|
||||||
|
Direction: core.DirectionRecvonly,
|
||||||
|
Codecs: []*core.Codec{
|
||||||
|
{
|
||||||
|
Name: name,
|
||||||
|
ClockRate: uint32(video.SampleRate),
|
||||||
|
PayloadType: 96,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
c.medias = append(c.medias, media)
|
||||||
|
|
||||||
iceServersBytes, err := json.Marshal(&webRTCConfigResponse.Result.P2PConfig.Ices)
|
iceServersBytes, err := json.Marshal(&webRTCConfigResponse.Result.P2PConfig.Ices)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to marshal ICE servers: %w", err)
|
return fmt.Errorf("failed to marshal ICE servers: %w", err)
|
||||||
@@ -282,4 +358,13 @@ func(c *TuyaClient) calBusinessSign(ts int64) string {
|
|||||||
val := md5.Sum([]byte(data))
|
val := md5.Sum([]byte(data))
|
||||||
res := fmt.Sprintf("%X", val)
|
res := fmt.Sprintf("%X", val)
|
||||||
return res
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
func contains(slice []int, val int) bool {
|
||||||
|
for _, item := range slice {
|
||||||
|
if item == val {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
+8
-32
@@ -58,8 +58,8 @@ func Dial(rawURL string) (*Client, error) {
|
|||||||
|
|
||||||
conf := pion.Configuration{
|
conf := pion.Configuration{
|
||||||
ICEServers: client.api.iceServers,
|
ICEServers: client.api.iceServers,
|
||||||
// ICETransportPolicy: pion.ICETransportPolicyAll,
|
ICETransportPolicy: pion.ICETransportPolicyAll,
|
||||||
// BundlePolicy: pion.BundlePolicyMaxBundle,
|
BundlePolicy: pion.BundlePolicyMaxBundle,
|
||||||
}
|
}
|
||||||
|
|
||||||
api, err := webrtc.NewAPI()
|
api, err := webrtc.NewAPI()
|
||||||
@@ -99,14 +99,15 @@ func Dial(rawURL string) (*Client, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err = pc.SetRemoteDescription(desc); err != nil {
|
if err = pc.SetRemoteDescription(desc); err != nil {
|
||||||
|
client.Stop()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
prod.SetAnswer(answer.Sdp)
|
if err = prod.SetAnswer(answer.Sdp); err != nil {
|
||||||
if err != nil {
|
|
||||||
client.Stop()
|
client.Stop()
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
prod.SDP = answer.Sdp
|
prod.SDP = answer.Sdp
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,32 +149,8 @@ func Dial(rawURL string) (*Client, error) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
medias := []*core.Media{
|
|
||||||
{
|
|
||||||
Kind: core.KindAudio,
|
|
||||||
Direction: core.DirectionSendRecv,
|
|
||||||
Codecs: []*core.Codec{
|
|
||||||
{
|
|
||||||
Name: "PCMU",
|
|
||||||
ClockRate: 8000,
|
|
||||||
Channels: 1,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Kind: core.KindVideo,
|
|
||||||
Direction: core.DirectionRecvonly,
|
|
||||||
Codecs: []*core.Codec{
|
|
||||||
{
|
|
||||||
Name: "H264",
|
|
||||||
ClockRate: 90000,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create offer
|
// Create offer
|
||||||
offer, err := prod.CreateOffer(medias)
|
offer, err := prod.CreateOffer(client.api.medias)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
client.api.Close()
|
client.api.Close()
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -231,7 +208,6 @@ func (c *Client) Stop() error {
|
|||||||
|
|
||||||
if c.api != nil {
|
if c.api != nil {
|
||||||
c.api.Close()
|
c.api.Close()
|
||||||
c.api = nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -63,12 +63,12 @@ func (c *Conn) SetAnswer(answer string) (err error) {
|
|||||||
SDP: fakeFormatsInAnswer(c.pc.LocalDescription().SDP, answer),
|
SDP: fakeFormatsInAnswer(c.pc.LocalDescription().SDP, answer),
|
||||||
}
|
}
|
||||||
if err = c.pc.SetRemoteDescription(desc); err != nil {
|
if err = c.pc.SetRemoteDescription(desc); err != nil {
|
||||||
return
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
sd := &sdp.SessionDescription{}
|
sd := &sdp.SessionDescription{}
|
||||||
if err = sd.Unmarshal([]byte(answer)); err != nil {
|
if err = sd.Unmarshal([]byte(answer)); err != nil {
|
||||||
return
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Medias = UnmarshalMedias(sd.MediaDescriptions)
|
c.Medias = UnmarshalMedias(sd.MediaDescriptions)
|
||||||
|
|||||||
Reference in New Issue
Block a user