mirror of
https://github.com/AlexxIT/go2rtc.git
synced 2025-10-06 16:57:29 +08:00
Refactor WebRTC candidates processing
This commit is contained in:
@@ -4,39 +4,67 @@ import (
|
|||||||
"github.com/AlexxIT/go2rtc/cmd/api"
|
"github.com/AlexxIT/go2rtc/cmd/api"
|
||||||
"github.com/AlexxIT/go2rtc/pkg/webrtc"
|
"github.com/AlexxIT/go2rtc/pkg/webrtc"
|
||||||
"github.com/pion/sdp/v3"
|
"github.com/pion/sdp/v3"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
var candidates []string
|
type Address struct {
|
||||||
var networks = []string{"udp", "tcp"}
|
Host string
|
||||||
|
Port int
|
||||||
|
}
|
||||||
|
|
||||||
|
var addresses []Address
|
||||||
|
|
||||||
func AddCandidate(address string) {
|
func AddCandidate(address string) {
|
||||||
candidates = append(candidates, address)
|
var port int
|
||||||
|
|
||||||
|
// try to get port from address string
|
||||||
|
if i := strings.LastIndexByte(address, ':'); i > 0 {
|
||||||
|
if v, _ := strconv.Atoi(address[i+1:]); v != 0 {
|
||||||
|
address = address[:i]
|
||||||
|
port = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// use default WebRTC port
|
||||||
|
if port == 0 {
|
||||||
|
port, _ = strconv.Atoi(Port)
|
||||||
|
}
|
||||||
|
|
||||||
|
addresses = append(addresses, Address{Host: address, Port: port})
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetCandidates() (candidates []string) {
|
||||||
|
for _, address := range addresses {
|
||||||
|
// using stun server for receive public IP-address
|
||||||
|
if address.Host == "stun" {
|
||||||
|
ip, err := webrtc.GetCachedPublicIP()
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// this is a copy, original host unchanged
|
||||||
|
address.Host = ip.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
candidates = append(
|
||||||
|
candidates,
|
||||||
|
webrtc.CandidateHostUDP(address.Host, address.Port),
|
||||||
|
webrtc.CandidateHostTCPPassive(address.Host, address.Port),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func asyncCandidates(tr *api.Transport) {
|
func asyncCandidates(tr *api.Transport) {
|
||||||
for _, address := range candidates {
|
for _, candidate := range GetCandidates() {
|
||||||
address, err := webrtc.LookupIP(address)
|
log.Trace().Str("candidate", candidate).Msg("[webrtc] config")
|
||||||
if err != nil {
|
tr.Write(&api.Message{Type: "webrtc/candidate", Value: candidate})
|
||||||
log.Warn().Err(err).Caller().Send()
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, network := range networks {
|
|
||||||
cand, err := webrtc.NewCandidate(network, address)
|
|
||||||
if err != nil {
|
|
||||||
log.Warn().Err(err).Caller().Send()
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Trace().Str("candidate", cand).Msg("[webrtc] config")
|
|
||||||
|
|
||||||
tr.Write(&api.Message{Type: "webrtc/candidate", Value: cand})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func syncCanditates(answer string) (string, error) {
|
func syncCanditates(answer string) (string, error) {
|
||||||
if len(candidates) == 0 {
|
if len(addresses) == 0 {
|
||||||
return answer, nil
|
return answer, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,23 +80,8 @@ func syncCanditates(answer string) (string, error) {
|
|||||||
md.Attributes = md.Attributes[:len(md.Attributes)-1]
|
md.Attributes = md.Attributes[:len(md.Attributes)-1]
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, address := range candidates {
|
for _, candidate := range GetCandidates() {
|
||||||
var err error
|
md.WithPropertyAttribute(candidate)
|
||||||
address, err = webrtc.LookupIP(address)
|
|
||||||
if err != nil {
|
|
||||||
log.Warn().Err(err).Msg("[webrtc] candidate")
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, network := range networks {
|
|
||||||
cand, err := webrtc.NewCandidate(network, address)
|
|
||||||
if err != nil {
|
|
||||||
log.Warn().Err(err).Msg("[webrtc] candidate")
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
md.WithPropertyAttribute(cand)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if end {
|
if end {
|
||||||
|
@@ -58,7 +58,9 @@ func Init() {
|
|||||||
return pionAPI.NewPeerConnection(pionConf)
|
return pionAPI.NewPeerConnection(pionConf)
|
||||||
}
|
}
|
||||||
|
|
||||||
candidates = cfg.Mod.Candidates
|
for _, candidate := range cfg.Mod.Candidates {
|
||||||
|
AddCandidate(candidate)
|
||||||
|
}
|
||||||
|
|
||||||
api.HandleWS("webrtc", asyncHandler)
|
api.HandleWS("webrtc", asyncHandler)
|
||||||
api.HandleWS("webrtc/offer", asyncHandler)
|
api.HandleWS("webrtc/offer", asyncHandler)
|
||||||
|
@@ -7,6 +7,7 @@ import (
|
|||||||
"github.com/pion/ice/v2"
|
"github.com/pion/ice/v2"
|
||||||
"github.com/pion/stun"
|
"github.com/pion/stun"
|
||||||
"github.com/pion/webrtc/v3"
|
"github.com/pion/webrtc/v3"
|
||||||
|
"hash/crc32"
|
||||||
"net"
|
"net"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -157,3 +158,35 @@ func MimeType(codec *streamer.Codec) string {
|
|||||||
}
|
}
|
||||||
panic("not implemented")
|
panic("not implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const PriorityHost = (1 << 24) * uint32(126)
|
||||||
|
const PriorityLocalUDP = (1 << 8) * uint32(65535)
|
||||||
|
const PriorityLocalTCPPassive = (1 << 8) * uint32((1<<13)*4+8191)
|
||||||
|
const PriorityComponentRTP = uint32(256 - ice.ComponentRTP)
|
||||||
|
|
||||||
|
func CandidateHostUDP(host string, port int) string {
|
||||||
|
foundation := crc32.ChecksumIEEE([]byte("host" + host + "udp4"))
|
||||||
|
priority := PriorityHost + PriorityLocalUDP + PriorityComponentRTP
|
||||||
|
|
||||||
|
// 1. Foundation
|
||||||
|
// 2. Component, always 1 because RTP
|
||||||
|
// 3. udp or tcp
|
||||||
|
// 4. Priority
|
||||||
|
// 5. Host - IP4 or IP6 or domain name
|
||||||
|
// 6. Port
|
||||||
|
// 7. typ host
|
||||||
|
return fmt.Sprintf(
|
||||||
|
"candidate:%d 1 udp %d %s %d typ host",
|
||||||
|
foundation, priority, host, port,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func CandidateHostTCPPassive(address string, port int) string {
|
||||||
|
foundation := crc32.ChecksumIEEE([]byte("host" + address + "tcp4"))
|
||||||
|
priority := PriorityHost + PriorityLocalTCPPassive + PriorityComponentRTP
|
||||||
|
|
||||||
|
return fmt.Sprintf(
|
||||||
|
"candidate:%d 1 tcp %d %s %d typ host tcptype passive",
|
||||||
|
foundation, priority, address, port,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
@@ -5,19 +5,31 @@ import (
|
|||||||
"github.com/pion/sdp/v3"
|
"github.com/pion/sdp/v3"
|
||||||
"github.com/pion/webrtc/v3"
|
"github.com/pion/webrtc/v3"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestName(t *testing.T) {
|
func TestCandidates(t *testing.T) {
|
||||||
i, _ := ice.NewCandidateHost(&ice.CandidateHostConfig{
|
conf := &ice.CandidateHostConfig{
|
||||||
|
Network: "udp",
|
||||||
|
Address: "192.168.1.123",
|
||||||
|
Port: 8555,
|
||||||
|
Component: ice.ComponentRTP,
|
||||||
|
}
|
||||||
|
cand, err := ice.NewCandidateHost(conf)
|
||||||
|
require.Nil(t, err)
|
||||||
|
assert.Equal(t, "candidate:"+cand.Marshal(), CandidateHostUDP(conf.Address, conf.Port))
|
||||||
|
|
||||||
|
conf = &ice.CandidateHostConfig{
|
||||||
Network: "tcp",
|
Network: "tcp",
|
||||||
Address: "192.168.1.123",
|
Address: "192.168.1.123",
|
||||||
Port: 8555,
|
Port: 8555,
|
||||||
Component: ice.ComponentRTP,
|
Component: ice.ComponentRTP,
|
||||||
TCPType: ice.TCPTypePassive,
|
TCPType: ice.TCPTypePassive,
|
||||||
})
|
}
|
||||||
a := i.Marshal()
|
cand, err = ice.NewCandidateHost(conf)
|
||||||
println(a)
|
require.Nil(t, err)
|
||||||
|
assert.Equal(t, "candidate:"+cand.Marshal(), CandidateHostTCPPassive(conf.Address, conf.Port))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPublicIP(t *testing.T) {
|
func TestPublicIP(t *testing.T) {
|
||||||
|
Reference in New Issue
Block a user