fix webrtc client gathering, #259.

This commit is contained in:
Miroslav Šedivý 2023-03-18 00:49:25 +01:00
parent 0cebe465a2
commit 9daf83cc52
9 changed files with 70 additions and 17 deletions

View File

@ -203,11 +203,12 @@ export abstract class BaseClient extends EventEmitter<BaseEvents> {
return return
} }
this._peer = new RTCPeerConnection()
if (lite !== true) { if (lite !== true) {
this._peer = new RTCPeerConnection({ this._peer = new RTCPeerConnection({
iceServers: servers, iceServers: servers,
}) })
} else {
this._peer = new RTCPeerConnection()
} }
this._peer.onconnectionstatechange = () => { this._peer.onconnectionstatechange = () => {
@ -251,11 +252,28 @@ export abstract class BaseClient extends EventEmitter<BaseEvents> {
this._peer.ontrack = this.onTrack.bind(this) this._peer.ontrack = this.onTrack.bind(this)
this._peer.onicecandidate = (event: RTCPeerConnectionIceEvent) => {
if (!event.candidate) {
this.emit('debug', `sent all local ICE candidates`)
return
}
const init = event.candidate.toJSON()
this.emit('debug', `sending local ICE candidate`, init)
this._ws!.send(
JSON.stringify({
event: EVENT.SIGNAL.CANDIDATE,
data: JSON.stringify(init),
}),
)
}
this._peer.onnegotiationneeded = async () => { this._peer.onnegotiationneeded = async () => {
this.emit('warn', `negotiation is needed`) this.emit('warn', `negotiation is needed`)
const d = await this._peer!.createOffer() const d = await this._peer!.createOffer()
this._peer!.setLocalDescription(d) await this._peer!.setLocalDescription(d)
this._ws!.send( this._ws!.send(
JSON.stringify({ JSON.stringify({
@ -277,10 +295,10 @@ export abstract class BaseClient extends EventEmitter<BaseEvents> {
return return
} }
this._peer.setRemoteDescription({ type: 'offer', sdp }) await this._peer.setRemoteDescription({ type: 'offer', sdp })
for (const candidate of this._candidates) { for (const candidate of this._candidates) {
this._peer.addIceCandidate(candidate) await this._peer.addIceCandidate(candidate)
} }
this._candidates = [] this._candidates = []
@ -310,7 +328,7 @@ export abstract class BaseClient extends EventEmitter<BaseEvents> {
return return
} }
this._peer.setRemoteDescription({ type: 'answer', sdp }) await this._peer.setRemoteDescription({ type: 'answer', sdp })
} }
private async onMessage(e: MessageEvent) { private async onMessage(e: MessageEvent) {

View File

@ -12,6 +12,7 @@
- Fixed stereo problem in chromium-based browsers, where it was only as mono by adding `stereo=1` to opus SDP to clients answer. - Fixed stereo problem in chromium-based browsers, where it was only as mono by adding `stereo=1` to opus SDP to clients answer.
- Fixed keysym mapping for unknown keycodes, which was causing some key combinations to not work on some keyboards. - Fixed keysym mapping for unknown keycodes, which was causing some key combinations to not work on some keyboards.
- Fixed a bug where `max_fps=0` would lead to an invalid pipeline. - Fixed a bug where `max_fps=0` would lead to an invalid pipeline.
- Fixed client side webrtc ICE gathering, so that neko can be used without exposed ports, only with STUN and TURN servers.
### Misc ### Misc
- Updated to go 1.19 and Node 18, removed go-events as dependency (by @mbattista). - Updated to go 1.19 and Node 18, removed go-events as dependency (by @mbattista).

View File

@ -131,6 +131,17 @@ func (session *Session) SignalLocalAnswer(sdp string) error {
}) })
} }
func (session *Session) SignalLocalCandidate(data string) error {
if session.socket == nil {
return nil
}
session.peer.SetCandidate(data)
return session.socket.Send(&message.SignalCandidate{
Event: event.SIGNAL_CANDIDATE,
Data: data,
})
}
func (session *Session) SignalRemoteOffer(sdp string) error { func (session *Session) SignalRemoteOffer(sdp string) error {
if session.peer == nil { if session.peer == nil {
return nil return nil
@ -154,14 +165,12 @@ func (session *Session) SignalRemoteAnswer(sdp string) error {
return session.peer.SetAnswer(sdp) return session.peer.SetAnswer(sdp)
} }
func (session *Session) SignalCandidate(data string) error { func (session *Session) SignalRemoteCandidate(data string) error {
if session.socket == nil { if session.socket == nil {
return nil return nil
} }
return session.socket.Send(&message.SignalCandidate{ session.logger.Info().Msg("signal update - RemoteCandidate")
Event: event.SIGNAL_CANDIDATE, return session.peer.SetCandidate(data)
Data: data,
})
} }
func (session *Session) destroy() error { func (session *Session) destroy() error {

View File

@ -40,9 +40,10 @@ type Session interface {
Send(v interface{}) error Send(v interface{}) error
SignalLocalOffer(sdp string) error SignalLocalOffer(sdp string) error
SignalLocalAnswer(sdp string) error SignalLocalAnswer(sdp string) error
SignalLocalCandidate(data string) error
SignalRemoteOffer(sdp string) error SignalRemoteOffer(sdp string) error
SignalRemoteAnswer(sdp string) error SignalRemoteAnswer(sdp string) error
SignalCandidate(data string) error SignalRemoteCandidate(data string) error
} }
type SessionManager interface { type SessionManager interface {

View File

@ -21,6 +21,7 @@ type Peer interface {
CreateAnswer() (string, error) CreateAnswer() (string, error)
SetOffer(sdp string) error SetOffer(sdp string) error
SetAnswer(sdp string) error SetAnswer(sdp string) error
SetCandidate(candidateString string) error
WriteData(v interface{}) error WriteData(v interface{}) error
Destroy() error Destroy() error
} }

View File

@ -1,6 +1,7 @@
package webrtc package webrtc
import ( import (
"encoding/json"
"sync" "sync"
"github.com/pion/webrtc/v3" "github.com/pion/webrtc/v3"
@ -49,6 +50,16 @@ func (peer *Peer) SetAnswer(sdp string) error {
return peer.connection.SetRemoteDescription(webrtc.SessionDescription{SDP: sdp, Type: webrtc.SDPTypeAnswer}) return peer.connection.SetRemoteDescription(webrtc.SessionDescription{SDP: sdp, Type: webrtc.SDPTypeAnswer})
} }
func (peer *Peer) SetCandidate(candidateString string) error {
var candidate webrtc.ICECandidateInit
err := json.Unmarshal([]byte(candidateString), &candidate)
if err != nil {
return err
}
return peer.connection.AddICECandidate(candidate)
}
func (peer *Peer) WriteData(v interface{}) error { func (peer *Peer) WriteData(v interface{}) error {
peer.mu.Lock() peer.mu.Lock()
defer peer.mu.Unlock() defer peer.mu.Unlock()

View File

@ -123,7 +123,6 @@ func (manager *WebRTCManager) initAPI() error {
LoggerFactory: logger, LoggerFactory: logger,
} }
_ = settings.SetEphemeralUDPPortRange(manager.config.EphemeralMin, manager.config.EphemeralMax)
settings.SetNAT1To1IPs(manager.config.NAT1To1IPs, webrtc.ICECandidateTypeHost) settings.SetNAT1To1IPs(manager.config.NAT1To1IPs, webrtc.ICECandidateTypeHost)
settings.SetICETimeouts(6*time.Second, 6*time.Second, 3*time.Second) settings.SetICETimeouts(6*time.Second, 6*time.Second, 3*time.Second)
settings.SetSRTPReplayProtectionWindow(512) settings.SetSRTPReplayProtectionWindow(512)
@ -168,12 +167,15 @@ func (manager *WebRTCManager) initAPI() error {
networkType = append(networkType, webrtc.NetworkTypeUDP4) networkType = append(networkType, webrtc.NetworkTypeUDP4)
manager.logger.Info().Int("port", manager.config.UDPMUX).Msg("using UDP MUX") manager.logger.Info().Int("port", manager.config.UDPMUX).Msg("using UDP MUX")
} else if manager.config.EphemeralMax != 0 {
_ = settings.SetEphemeralUDPPortRange(manager.config.EphemeralMin, manager.config.EphemeralMax)
networkType = append(networkType,
webrtc.NetworkTypeUDP4,
webrtc.NetworkTypeUDP6,
)
} }
// Enable support for TCP and UDP ICE candidates settings.SetNetworkTypes(networkType)
if len(networkType) > 0 {
settings.SetNetworkTypes(networkType)
}
// Create MediaEngine with selected codecs // Create MediaEngine with selected codecs
engine := webrtc.MediaEngine{} engine := webrtc.MediaEngine{}
@ -299,7 +301,7 @@ func (manager *WebRTCManager) CreatePeer(id string, session types.Session) (type
return return
} }
if err := session.SignalCandidate(string(candidateString)); err != nil { if err := session.SignalLocalCandidate(string(candidateString)); err != nil {
manager.logger.Warn().Err(err).Msg("sending SignalCandidate failed") manager.logger.Warn().Err(err).Msg("sending SignalCandidate failed")
return return
} }

View File

@ -87,6 +87,12 @@ func (h *MessageHandler) Message(id string, raw []byte) error {
utils.Unmarshal(payload, raw, func() error { utils.Unmarshal(payload, raw, func() error {
return h.signalRemoteAnswer(id, session, payload) return h.signalRemoteAnswer(id, session, payload)
}), "%s failed", header.Event) }), "%s failed", header.Event)
case event.SIGNAL_CANDIDATE:
payload := &message.SignalCandidate{}
return errors.Wrapf(
utils.Unmarshal(payload, raw, func() error {
return h.signalRemoteCandidate(id, session, payload)
}), "%s failed", header.Event)
// Control Events // Control Events
case event.CONTROL_RELEASE: case event.CONTROL_RELEASE:

View File

@ -45,3 +45,7 @@ func (h *MessageHandler) signalRemoteAnswer(id string, session types.Session, pa
return nil return nil
} }
func (h *MessageHandler) signalRemoteCandidate(id string, session types.Session, payload *message.SignalCandidate) error {
return session.SignalRemoteCandidate(payload.Data)
}