mirror of
https://github.com/balzack/databag.git
synced 2025-03-13 00:50:03 +00:00
connecting rtc peer
This commit is contained in:
parent
7a36d4843d
commit
d5ada715af
@ -11,7 +11,7 @@ var bridgeRelay BridgeRelay;
|
||||
const BridgeKeepAlive = 15
|
||||
|
||||
type BridgeStatus struct {
|
||||
status string
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
type Bridge struct {
|
||||
@ -28,13 +28,13 @@ type Bridge struct {
|
||||
|
||||
type BridgeRelay struct {
|
||||
sync sync.Mutex
|
||||
bridges []Bridge
|
||||
bridges []*Bridge
|
||||
}
|
||||
|
||||
func (s *BridgeRelay) AddBridge(accountId uint, callId string, callerToken string, calleeToken string) {
|
||||
s.sync.Lock()
|
||||
defer s.sync.Unlock()
|
||||
bridge := Bridge{
|
||||
bridge := &Bridge{
|
||||
accountId: accountId,
|
||||
callId: callId,
|
||||
expires: time.Now().Unix() + (BridgeKeepAlive * 3),
|
||||
@ -45,8 +45,8 @@ func (s *BridgeRelay) AddBridge(accountId uint, callId string, callerToken strin
|
||||
s.bridges = append(s.bridges, bridge)
|
||||
}
|
||||
|
||||
func setStatus(bridge Bridge, status string) {
|
||||
msg, _ := json.Marshal(BridgeStatus{ status: status })
|
||||
func setStatus(bridge *Bridge, status string) {
|
||||
msg, _ := json.Marshal(BridgeStatus{ Status: status })
|
||||
if bridge.caller != nil {
|
||||
if err := bridge.caller.WriteMessage(websocket.TextMessage, msg); err != nil {
|
||||
LogMsg("failed to notify bridge status");
|
||||
@ -63,7 +63,7 @@ func (s *BridgeRelay) KeepAlive(accountId uint, callId string) {
|
||||
s.sync.Lock()
|
||||
defer s.sync.Unlock()
|
||||
now := time.Now().Unix()
|
||||
var bridges []Bridge
|
||||
var bridges []*Bridge
|
||||
for _, bridge := range s.bridges {
|
||||
if bridge.expires > now {
|
||||
bridges = append(bridges, bridge)
|
||||
@ -90,7 +90,7 @@ func (s *BridgeRelay) KeepAlive(accountId uint, callId string) {
|
||||
func (s *BridgeRelay) RemoveBridge(accountId uint, callId string, cardId string) {
|
||||
s.sync.Lock()
|
||||
defer s.sync.Unlock()
|
||||
var bridges []Bridge
|
||||
var bridges []*Bridge
|
||||
for _, bridge := range s.bridges {
|
||||
if bridge.callId == callId && bridge.accountId == accountId && (bridge.cardId == cardId || cardId == "") {
|
||||
setStatus(bridge, "closed");
|
||||
|
@ -13,10 +13,12 @@ export function useRingContext() {
|
||||
});
|
||||
const access = useRef(null);
|
||||
|
||||
const EXPIRE = 3000000
|
||||
const EXPIRE = 3000
|
||||
const RING = 2000
|
||||
const ringing = useRef(new Map());
|
||||
const calling = useRef(null);
|
||||
const ws = useRef(null);
|
||||
const pc = useRef(null);
|
||||
|
||||
const updateState = (value) => {
|
||||
setState((s) => ({ ...s, ...value }))
|
||||
@ -43,7 +45,7 @@ export function useRingContext() {
|
||||
updateState({ ringing: ringing.current });
|
||||
setTimeout(() => {
|
||||
updateState({ ringing: ringing.current });
|
||||
}, 3000);
|
||||
}, EXPIRE);
|
||||
},
|
||||
ignore: (cardId, callId) => {
|
||||
const key = `${cardId}:${callId}`
|
||||
@ -78,20 +80,73 @@ export function useRingContext() {
|
||||
// connect signal socket
|
||||
calling.current = { state: "connecting", callId, contactNode, contactToken, host: false };
|
||||
updateState({ callStatus: "connecting" });
|
||||
|
||||
// form peer connection
|
||||
pc.current = new RTCPeerConnection();
|
||||
pc.current.ontrack = ({streams: [stream]}) => {
|
||||
console.log("ON TRACK");
|
||||
};
|
||||
pc.current.onicecandidate = ({candidate}) => {
|
||||
ws.current.send(JSON.stringify({ candidate }));
|
||||
};
|
||||
pc.current.onnegotiationneeded = async () => {
|
||||
if (calling.current.state === 'connected') {
|
||||
const offer = await pc.current.createOffer();
|
||||
if (pc.current.signalingState !== 'stable') {
|
||||
return;
|
||||
}
|
||||
await pc.current.setLocalDescription(offer);
|
||||
ws.current.send(JSON.stringify({ description: pc.current.localDescription }));
|
||||
}
|
||||
};
|
||||
|
||||
const stream = await whiteNoise();
|
||||
pc.current.addTransceiver(stream.getTracks()[0], {streams: [stream]});
|
||||
|
||||
ws.current = createWebsocket(`wss://${contactNode}/signal`);
|
||||
ws.current.onmessage = (ev) => {
|
||||
ws.current.onmessage = async (ev) => {
|
||||
// handle messages [impolite]
|
||||
console.log(ev);
|
||||
try {
|
||||
const signal = JSON.parse(ev.data);
|
||||
if (signal.description) {
|
||||
if (signal.description.type === 'offer' && pc.current.signalingState !== 'stable') {
|
||||
return; //rudely ignore
|
||||
}
|
||||
await pc.current.setRemoteDescription(signal.description);
|
||||
if (signal.description.type === 'offer') {
|
||||
const answer = await pc.current.createAnswer();
|
||||
await pc.current.setLocalDescription(answer);
|
||||
ws.current.send(JSON.stringify({ description: pc.current.localDescription }));
|
||||
}
|
||||
}
|
||||
else if (signal.candidate) {
|
||||
await pc.current.addIceCandidate(signal.candidate);
|
||||
}
|
||||
console.log(signal);
|
||||
}
|
||||
catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
}
|
||||
ws.current.onclose = (e) => {
|
||||
// update state to disconnected
|
||||
pc.current.close();
|
||||
calling.current = null;
|
||||
updateState({ calling: null });
|
||||
}
|
||||
ws.current.onopen = () => {
|
||||
ws.current.onopen = async () => {
|
||||
calling.current.state = "connected"
|
||||
updateState({ callStatus: "connected" });
|
||||
ws.current.send(JSON.stringify({ AppToken: calleeToken }))
|
||||
|
||||
try {
|
||||
const offer = await pc.current.createOffer();
|
||||
await pc.current.setLocalDescription(offer);
|
||||
ws.current.send(JSON.stringify({ description: pc.current.localDescription }));
|
||||
}
|
||||
catch(err) {
|
||||
console.log(err);
|
||||
}
|
||||
}
|
||||
ws.current.error = (e) => {
|
||||
console.log(e)
|
||||
@ -124,10 +179,16 @@ export function useRingContext() {
|
||||
|
||||
// create call
|
||||
const call = await addCall(access.current, cardId);
|
||||
const { callId, keepAlive, callerToken, calleeToken } = call;
|
||||
const { id, keepAlive, callerToken, calleeToken } = call;
|
||||
try {
|
||||
await addContactRing(contactNode, contactToken, { index, callId: id, calleeToken });
|
||||
}
|
||||
catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
const aliveInterval = setInterval(async () => {
|
||||
try {
|
||||
await keepCall(access.current, call.callId);
|
||||
await keepCall(access.current, id);
|
||||
}
|
||||
catch (err) {
|
||||
console.log(err);
|
||||
@ -136,23 +197,74 @@ export function useRingContext() {
|
||||
let index = 0;
|
||||
const ringInterval = setInterval(async () => {
|
||||
try {
|
||||
await addContactRing(contactNode, contactToken, { index, callId, calleeToken });
|
||||
await addContactRing(contactNode, contactToken, { index, callId: id, calleeToken });
|
||||
index += 1;
|
||||
}
|
||||
catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
}, 3000);
|
||||
calling.current = { state: "connecting", callId, host: true };
|
||||
}, RING);
|
||||
|
||||
calling.current = { state: "connecting", callId: id, host: true };
|
||||
updateState({ callStatus: "connecting" });
|
||||
|
||||
// form peer connection
|
||||
pc.current = new RTCPeerConnection();
|
||||
pc.current.ontrack = ({streams: [stream]}) => {
|
||||
console.log("ON TRACK");
|
||||
};
|
||||
pc.current.onicecandidate = ({candidate}) => {
|
||||
ws.current.send(JSON.stringify({ candidate }));
|
||||
};
|
||||
pc.current.onnegotiationneeded = async () => {
|
||||
if (calling.current.state === 'connected') {
|
||||
const offer = await pc.current.createOffer();
|
||||
if (pc.current.signalingState !== 'stable') {
|
||||
return;
|
||||
}
|
||||
await pc.current.setLocalDescription(offer);
|
||||
ws.current.send(JSON.stringify({ description: pc.current.localDescription }));
|
||||
}
|
||||
};
|
||||
|
||||
const stream = await whiteNoise();
|
||||
pc.current.addTransceiver(stream.getTracks()[0], {streams: [stream]});
|
||||
|
||||
const protocol = window.location.protocol === 'http:' ? 'ws://' : 'wss://';
|
||||
ws.current = createWebsocket(`${protocol}${window.location.host}/signal`);
|
||||
ws.current.onmessage = (ev) => {
|
||||
ws.current.onmessage = async (ev) => {
|
||||
// handle messages [polite]
|
||||
// on connected stop ringing
|
||||
console.log(ev);
|
||||
try {
|
||||
const signal = JSON.parse(ev.data);
|
||||
if (signal.status) {
|
||||
if (calling.current.state !== 'connected' && signal.status === 'connected') {
|
||||
clearInterval(ringInterval);
|
||||
calling.current.state = 'connected';
|
||||
updateState({ callStatus: "connected" });
|
||||
}
|
||||
}
|
||||
else if (signal.description) {
|
||||
if (signal.description.type === 'offer' && pc.current.signalingState !== 'stable') {
|
||||
await pc.current.setLocalDescription({ type: "rollback" });
|
||||
}
|
||||
await pc.current.setRemoteDescription(signal.description);
|
||||
if (signal.description.type === 'offer') {
|
||||
const answer = await pc.current.createAnswer();
|
||||
await pc.current.setLocalDescription(answer);
|
||||
ws.current.send(JSON.stringify({ description: pc.current.localDescription }));
|
||||
}
|
||||
}
|
||||
else if (signal.candidate) {
|
||||
await pc.current.addIceCandidate(signal.candidate);
|
||||
}
|
||||
console.log(signal);
|
||||
}
|
||||
catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
}
|
||||
ws.current.onclose = (e) => {
|
||||
pc.current.close();
|
||||
clearInterval(ringInterval);
|
||||
clearInterval(aliveInterval);
|
||||
calling.current = null;
|
||||
@ -173,4 +285,18 @@ export function useRingContext() {
|
||||
return { state, actions }
|
||||
}
|
||||
|
||||
function whiteNoise() {
|
||||
const canvas = Object.assign(document.createElement("canvas"), {width: 320, height: 240});
|
||||
const ctx = canvas.getContext('2d');
|
||||
ctx.fillRect(0, 0, 320, 240);
|
||||
const p = ctx.getImageData(0, 0, 320, 240);
|
||||
requestAnimationFrame(function draw(){
|
||||
for (var i = 0; i < p.data.length; i++) {
|
||||
p.data[i++] = p.data[i++] = p.data[i++] = Math.random() * 255;
|
||||
}
|
||||
ctx.putImageData(p, 0, 0);
|
||||
requestAnimationFrame(draw);
|
||||
});
|
||||
return canvas.captureStream();
|
||||
}
|
||||
|
||||
|
@ -49,9 +49,11 @@ export function useSession() {
|
||||
if (call.expires > expired && !call.status) {
|
||||
const { callId, cardId, calleeToken } = call;
|
||||
const contact = card.state.cards.get(cardId);
|
||||
const { imageSet, name, handle, node } = contact.data.cardProfile || {};
|
||||
const { imageSet, name, handle, node, guid } = contact.data.cardProfile || {};
|
||||
const { token } = contact.data.cardDetail;
|
||||
const contactToken = `${guid}.${token}`;
|
||||
const img = imageSet ? card.actions.getCardImageUrl(cardId) : 'avatar';
|
||||
ringing.push({ cardId, img, name, handle, node, callId, calleeToken });
|
||||
ringing.push({ cardId, img, name, handle, contactNode: node, callId, contactToken, calleeToken });
|
||||
}
|
||||
});
|
||||
updateState({ ringing });
|
||||
@ -144,7 +146,8 @@ export function useSession() {
|
||||
ring.actions.decline(call.cardId, call.callId);
|
||||
},
|
||||
accept: (call) => {
|
||||
ring.actions.accept(call.cardId, call.callId);
|
||||
const { cardId, callId, contactNode, contactToken, calleeToken } = call;
|
||||
ring.actions.accept(cardId, callId, contactNode, contactToken, calleeToken);
|
||||
},
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user