mirror of
https://github.com/giongto35/cloud-game.git
synced 2026-07-18 00:55:40 +00:00
Create data channels when pushed to the server
This commit is contained in:
parent
25f42ee789
commit
3388a0fbce
3 changed files with 77 additions and 54 deletions
|
|
@ -38,6 +38,9 @@ func (p *Peer) NewConnection(vCodec, aCodec string, onICECandidate func(ice any)
|
|||
}
|
||||
p.conn.OnConnectionStateChange(func(pcs webrtc.PeerConnectionState) {
|
||||
p.log.Debug().Msgf("WebRTC state change: %v", pcs)
|
||||
if pcs == webrtc.PeerConnectionStateConnected {
|
||||
p.log.Info().Msg("Connected")
|
||||
}
|
||||
})
|
||||
p.conn.OnICECandidate(p.handleICECandidate(onICECandidate))
|
||||
|
||||
|
|
@ -51,14 +54,24 @@ func (p *Peer) NewConnection(vCodec, aCodec string, onICECandidate func(ice any)
|
|||
return err
|
||||
}
|
||||
|
||||
p.conn.OnICEConnectionStateChange(p.handleICEState(func() { p.log.Info().Msg("Connected") }))
|
||||
p.conn.OnICEConnectionStateChange(p.handleICEState(func() {}))
|
||||
|
||||
p.conn.OnDataChannel(func(dc *webrtc.DataChannel) {
|
||||
p.log.Debug().Msgf("Added [%s] datachannel", dc.Label())
|
||||
if dc.Label() == "data" {
|
||||
if err := p.AddDataChannel(); err != nil {
|
||||
p.log.Error().Msgf("Failed to add data channel: %v", err)
|
||||
}
|
||||
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()) })
|
||||
}
|
||||
})
|
||||
|
||||
|
|
@ -212,9 +225,9 @@ func (p *Peer) handleICEState(onConnect func()) func(webrtc.ICEConnectionState)
|
|||
p.log.Error().Msgf("WebRTC connection fail! connection: %v, ice: %v, gathering: %v, signalling: %v",
|
||||
p.conn.ConnectionState(), p.conn.ICEConnectionState(), p.conn.ICEGatheringState(),
|
||||
p.conn.SignalingState())
|
||||
p.Disconnect()
|
||||
case webrtc.ICEConnectionStateClosed,
|
||||
webrtc.ICEConnectionStateDisconnected:
|
||||
// make ICE restart
|
||||
case webrtc.ICEConnectionStateDisconnected:
|
||||
case webrtc.ICEConnectionStateClosed:
|
||||
p.Disconnect()
|
||||
default:
|
||||
p.log.Debug().Msg("ICE state is not handled!")
|
||||
|
|
|
|||
|
|
@ -490,15 +490,13 @@ function handleWebrtcStart({ data, initiator }) {
|
|||
|
||||
const negotiate = () => {
|
||||
if (makingOffer) return;
|
||||
makingOffer = true;
|
||||
webrtc
|
||||
.offerSdp()
|
||||
.then((offer) => {
|
||||
if (!offer) return;
|
||||
log.debug("> offer", offer);
|
||||
api.server.initWebrtcStream({ initiator, sdpOffer: offer });
|
||||
})
|
||||
.finally(() => (makingOffer = false));
|
||||
// makingOffer = true;
|
||||
// webrtc
|
||||
// .offerSdp()
|
||||
// .then((offer) => {
|
||||
// if (!offer) return;
|
||||
// })
|
||||
// .finally(() => (makingOffer = false));
|
||||
};
|
||||
|
||||
const datachannel = (ch) => {
|
||||
|
|
@ -523,8 +521,12 @@ function handleWebrtcStart({ data, initiator }) {
|
|||
});
|
||||
|
||||
if (initiator) {
|
||||
negotiate();
|
||||
// negotiate();
|
||||
webrtc.createDataChannel({ onChannel: datachannel });
|
||||
webrtc.offerSdp().then((offer) => {
|
||||
if (!offer) return;
|
||||
api.server.initWebrtcStream({ initiator, sdpOffer: offer });
|
||||
});
|
||||
} else {
|
||||
api.server.initWebrtcStream();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,13 +3,15 @@ import { log } from "log";
|
|||
let /** @type {RTCPeerConnection} */ pc;
|
||||
let /** @type {Map<string, RTCDataChannel>} */ channels = new Map();
|
||||
let /** @type {MediaStream} */ stream;
|
||||
let /** @type {RTCLocalIceCandidateInit[]} */ candidateBuf = [];
|
||||
let handleSdpAnswer;
|
||||
let _initiator = false;
|
||||
|
||||
const ice = (() => {
|
||||
let /** @type {RTCIceCandidateInit[]} */ buf = [];
|
||||
let handleIceCandidate;
|
||||
|
||||
const END_OF_CANDIDATES = null;
|
||||
|
||||
const onIceCandidate = (/** @type {RTCPeerConnectionIceEvent} */ ev) => {
|
||||
if (!ev.candidate) return;
|
||||
log.debug(`[rtc] [ice] local`, ev.candidate);
|
||||
|
|
@ -50,6 +52,12 @@ const ice = (() => {
|
|||
onIceCandidateError,
|
||||
onIceGatheringStateChange,
|
||||
onIceConnectionStateChange,
|
||||
buf,
|
||||
new: (/** @type RTCIceCandidateInit */ candidate) => {
|
||||
return candidate
|
||||
? new RTCIceCandidate(candidate)
|
||||
: END_OF_CANDIDATES;
|
||||
},
|
||||
set handleIceCandidate(cb) {
|
||||
handleIceCandidate = cb;
|
||||
},
|
||||
|
|
@ -59,22 +67,33 @@ const ice = (() => {
|
|||
const isConnected = () => pc?.connectionState === "connected";
|
||||
const hasRemoteDescription = () => pc?.remoteDescription !== null;
|
||||
|
||||
const addRemoteCandidate = (data) => {
|
||||
if (!data) return;
|
||||
const candidate = new RTCIceCandidate(data);
|
||||
const addIceCandidate = (data) => {
|
||||
const candidate = ice.new(data);
|
||||
pc.addIceCandidate(candidate).catch((e) => {
|
||||
log.error("[rtc] [ice] remote candidate add failed", e.name);
|
||||
log.error("[rtc] [ice] remote add", e.name);
|
||||
});
|
||||
log.debug(`[rtc] [ice] added remote`, candidate);
|
||||
log.debug("[rtc] [ice] add", candidate);
|
||||
};
|
||||
|
||||
const flushRemoteCandidates = () => {
|
||||
if (!hasRemoteDescription() || candidateBuf.length === 0) return;
|
||||
const flushIceCandidates = () => {
|
||||
if (ice.buf.length === 0) return;
|
||||
|
||||
log.debug(`[rtc] [ice] remote candidate buf (${candidateBuf.length})`);
|
||||
log.debug(`[rtc] [ice] buf (${ice.buf.length}) flush`);
|
||||
let data = undefined;
|
||||
while (typeof (data = candidateBuf.shift()) !== "undefined") {
|
||||
addRemoteCandidate(data);
|
||||
while (typeof (data = ice.buf.shift()) !== "undefined") {
|
||||
addIceCandidate(data);
|
||||
}
|
||||
};
|
||||
|
||||
const _setRemoteDescription = async (sdp) => {
|
||||
try {
|
||||
await pc.setRemoteDescription(new RTCSessionDescription(sdp));
|
||||
log.debug(`[rtc] [sdp] Trickle ICE: ${pc.canTrickleIceCandidates}`);
|
||||
flushIceCandidates();
|
||||
return true;
|
||||
} catch (e) {
|
||||
log.error(`[rtc] [sdp] set remote error: ${e}`);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -100,6 +119,7 @@ const stop = () => {
|
|||
}
|
||||
if (pc) {
|
||||
ice.handleIceCandidate = null;
|
||||
ice.buf = [];
|
||||
handleSdpAnswer = null;
|
||||
pc.oniceconnectionstatechange = null;
|
||||
pc.onicegatheringstatechange = null;
|
||||
|
|
@ -116,7 +136,6 @@ const stop = () => {
|
|||
channel.close();
|
||||
}
|
||||
channels.clear();
|
||||
candidateBuf = [];
|
||||
log.debug("[rtc] WebRTC has been closed");
|
||||
};
|
||||
|
||||
|
|
@ -135,8 +154,9 @@ export const webrtc = {
|
|||
onIceCandidate,
|
||||
onSdpAnswer,
|
||||
} = {}) => {
|
||||
log.debug("[rtc] got remote ICE servers", iceServers);
|
||||
pc = new RTCPeerConnection({ iceCandidatePoolSize: 1, iceServers });
|
||||
iceServers = iceServers || [];
|
||||
log.debug("[rtc] ICE servers", iceServers);
|
||||
pc = new RTCPeerConnection({ iceServers });
|
||||
stream = new MediaStream();
|
||||
|
||||
_initiator = initiator;
|
||||
|
|
@ -203,19 +223,10 @@ export const webrtc = {
|
|||
) => {
|
||||
log.debug("[rtc] [sdp] remote SDP", sdp);
|
||||
|
||||
if (!pc) return;
|
||||
|
||||
try {
|
||||
await pc.setRemoteDescription(new RTCSessionDescription(sdp));
|
||||
} catch (e) {
|
||||
log.error(`[rtc] [sdp] remote offer error: ${e}`);
|
||||
if (!pc || !_setRemoteDescription(sdp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
log.debug(`[rtc] [sdp] Trickle ICE: ${pc.canTrickleIceCandidates}`);
|
||||
|
||||
flushRemoteCandidates();
|
||||
|
||||
if (_initiator) return;
|
||||
|
||||
try {
|
||||
|
|
@ -229,20 +240,17 @@ export const webrtc = {
|
|||
}
|
||||
},
|
||||
pushChannel,
|
||||
addCandidate: (
|
||||
/** @type {RTCLocalIceCandidateInit | string} */ candidate,
|
||||
) => {
|
||||
addCandidate: (/** @type {RTCIceCandidateInit | string} */ candidate) => {
|
||||
log.debug(`[rtc] [ice] remote`, candidate);
|
||||
|
||||
if (!pc) return;
|
||||
|
||||
if (hasRemoteDescription()) {
|
||||
addRemoteCandidate(candidate);
|
||||
} else {
|
||||
candidateBuf.push(candidate);
|
||||
if (!hasRemoteDescription()) {
|
||||
ice.buf.push(candidate);
|
||||
return;
|
||||
}
|
||||
|
||||
if (candidate === "") {
|
||||
flushRemoteCandidates();
|
||||
}
|
||||
addIceCandidate(candidate);
|
||||
},
|
||||
send: (chan, data) => {
|
||||
const ch = channels.get(chan);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue