Create the main data channel without negotiation

There is no point in previously pushing or pulling this channel, since we won't change any of its configuration parameters.
This commit is contained in:
sergystepanov 2026-06-07 11:43:15 +03:00
parent 67cd92da6b
commit 86ee0cb380
3 changed files with 60 additions and 70 deletions

View file

@ -36,6 +36,28 @@ func (p *Peer) NewConnection(vCodec, aCodec string, onICECandidate func(ice any)
if p.conn, err = p.api.NewPeer(); err != nil {
return
}
id := uint16(0)
negotiated := true
ordered := false
maxRetransmits := uint16(0)
p.d, err = p.AddChannel("data", &webrtc.DataChannelInit{
ID: &id,
Negotiated: &negotiated,
Ordered: &ordered,
MaxRetransmits: &maxRetransmits,
},
func(data []byte) {
if len(data) == 0 || p.OnMessage == nil {
return
}
p.OnMessage(data)
})
if err != nil {
return err
}
p.conn.OnConnectionStateChange(func(pcs webrtc.PeerConnectionState) {
p.log.Debug().Msgf("WebRTC state change: %v", pcs)
if pcs == webrtc.PeerConnectionStateConnected {
@ -58,21 +80,6 @@ func (p *Peer) NewConnection(vCodec, aCodec string, onICECandidate func(ice any)
p.conn.OnDataChannel(func(ch *webrtc.DataChannel) {
p.log.Debug().Msgf("Added [%s] datachannel", ch.Label())
if ch.Label() == "data" {
p.d = ch
ch.OnMessage(func(m webrtc.DataChannelMessage) {
if len(m.Data) == 0 || p.OnMessage == nil {
return
}
p.OnMessage(m.Data)
})
ch.OnOpen(func() {
p.log.Debug().Uint16("id", *ch.ID()).Msgf("Data channel [%v] opened", ch.Label())
})
ch.OnError(p.logx)
ch.OnClose(func() { p.log.Debug().Msgf("Data channel [%v] has been closed", ch.Label()) })
}
})
return nil
@ -100,15 +107,6 @@ func (p *Peer) AddTrack(id, label, codec string) (*webrtc.TrackLocalStaticSample
return track, nil
}
func (p *Peer) AddDataChannel() error {
return p.AddChannel("data", func(data []byte) {
if len(data) == 0 || p.OnMessage == nil {
return
}
p.OnMessage(data)
})
}
func (p *Peer) OfferAnswer(offer bool) (*webrtc.SessionDescription, error) {
opts := webrtc.OfferAnswerOptions{ICETricklingSupported: true}
@ -250,17 +248,30 @@ func (p *Peer) AddCandidate(candidate string, decoder Decoder) error {
return nil
}
func (p *Peer) AddChannel(label string, onMessage func([]byte)) error {
ch, err := p.addDataChannel(label)
func (p *Peer) AddChannel(label string, conf *webrtc.DataChannelInit, onMessage func([]byte)) (*webrtc.DataChannel, error) {
config := conf
if conf == nil {
ordered := false
maxRetransmits := uint16(0)
config = &webrtc.DataChannelInit{Ordered: &ordered, MaxRetransmits: &maxRetransmits}
}
ch, err := p.conn.CreateDataChannel(label, config)
if err != nil {
return err
}
if label == "data" {
p.d = ch
return nil, err
}
ch.OnOpen(func() {
p.log.Debug().Uint16("id", *ch.ID()).Msgf("Data channel [%v] opened", ch.Label())
})
ch.OnMessage(func(m webrtc.DataChannelMessage) { onMessage(m.Data) })
ch.OnError(p.logx)
ch.OnClose(func() {
p.log.Debug().Msgf("Data channel [%v] has been closed", ch.Label())
})
p.log.Debug().Msgf("Added [%v] chan", label)
return nil
return ch, nil
}
func (p *Peer) Disconnect() {
@ -274,22 +285,4 @@ func (p *Peer) Disconnect() {
p.log.Debug().Msg("WebRTC stop")
}
// addDataChannel creates new WebRTC data channel.
// Default params -- ordered: true, negotiated: false.
func (p *Peer) addDataChannel(label string) (*webrtc.DataChannel, error) {
ch, err := p.conn.CreateDataChannel(label, &webrtc.DataChannelInit{
Ordered: new(bool),
MaxRetransmits: new(uint16),
})
if err != nil {
return nil, err
}
ch.OnOpen(func() {
p.log.Debug().Uint16("id", *ch.ID()).Msgf("Data channel [%v] opened", ch.Label())
})
ch.OnError(p.logx)
ch.OnClose(func() { p.log.Debug().Msgf("Data channel [%v] has been closed", ch.Label()) })
return ch, nil
}
func (p *Peer) logx(err error) { p.log.Error().Err(err) }

View file

@ -46,11 +46,6 @@ func (c *coordinator) HandleInitWebrtcStream(rq api.InitWebrtcStreamRequest, w *
c.log.Error().Err(err).Msgf("cannot set remote SDP of peer [%v]", rq.Id)
return api.EmptyPacket
}
} else {
if err := peer.AddDataChannel(); err != nil {
c.log.Error().Err(err).Msgf("cannot add data channel for peer [%v]", rq.Id)
return api.EmptyPacket
}
}
lsdp, err := peer.OfferAnswer(!rq.Initiator)
@ -219,8 +214,8 @@ func (c *coordinator) HandleGameStart(rq api.StartGameRequest, w *Worker) api.Ou
s := room.WithWebRTC(user.Session)
s.OnMessage = func(data []byte) { r.App().Input(user.Index, byte(caged.RetroPad), data) }
if needsKbMouse {
_ = s.AddChannel("keyboard", func(data []byte) { r.App().Input(user.Index, byte(caged.Keyboard), data) })
_ = s.AddChannel("mouse", func(data []byte) { r.App().Input(user.Index, byte(caged.Mouse), data) })
_, _ = s.AddChannel("keyboard", nil, func(data []byte) { r.App().Input(user.Index, byte(caged.Keyboard), data) })
_, _ = s.AddChannel("mouse", nil, func(data []byte) { r.App().Input(user.Index, byte(caged.Mouse), data) })
}
c.RegisterRoom(r.Id())

View file

@ -123,6 +123,22 @@ export const webrtc = {
log.debug("[rtc] [config] ICE:", iceServers);
pc = new RTCPeerConnection({ iceServers });
// push datachannel
try {
let ch = pc.createDataChannel("data", {
negotiated: true,
id: 0,
ordered: false,
maxRetransmits: 0,
});
ch = onDataChannel ? onDataChannel(ch) : ch;
if (!ch) throw new Error("null channel");
channels.set(ch.label, ch);
} catch (e) {
log.error("[rtc] failed to create data channel", e);
return;
}
caller = initiator;
log.debug(`[rtc] ${caller ? "caller" : "callee"}`);
@ -173,20 +189,6 @@ export const webrtc = {
connectionTime = performance.now();
if (initiator) {
// push datachannel
try {
let ch = pc.createDataChannel("data", {
ordered: false,
maxRetransmits: 0,
});
ch = onDataChannel ? onDataChannel(ch) : ch;
if (!ch) throw new Error("null channel");
channels.set(ch.label, ch);
} catch (e) {
log.error("[rtc] failed to create data channel", e);
return;
}
offer().then((offer) => {
if (!offer) return;
signalling.init({ initiator, sdpOffer: offer });