mirror of
https://github.com/SrIzan10/helium.git
synced 2026-06-06 00:56:58 +00:00
fix: (ai gen) streaming stability improvementsk
This commit is contained in:
@@ -35,7 +35,7 @@ const isConnected = ref(false);
|
||||
const viewerStore = useViewerStore();
|
||||
const { code: codeRef } = storeToRefs(viewerStore);
|
||||
const wsUrl = useWebSocketUrl();
|
||||
const { send } = useWebSocket(wsUrl, {
|
||||
const { send, close: closeWebSocket } = useWebSocket(wsUrl, {
|
||||
autoReconnect: true,
|
||||
heartbeat: {
|
||||
message: JSON.stringify({ event: "ping" }),
|
||||
@@ -80,6 +80,18 @@ const { send } = useWebSocket(wsUrl, {
|
||||
if (peerConnection.connectionState === "connected") {
|
||||
viewerStore.setConnectionStatus("connected!");
|
||||
}
|
||||
|
||||
// Handle disconnection or failed connection
|
||||
if (
|
||||
peerConnection.connectionState === "disconnected" ||
|
||||
peerConnection.connectionState === "failed" ||
|
||||
peerConnection.connectionState === "closed"
|
||||
) {
|
||||
viewerStore.setConnectionStatus(
|
||||
`connection ${peerConnection.connectionState}`,
|
||||
);
|
||||
isConnected.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
peerConnection.oniceconnectionstatechange = () => {
|
||||
@@ -95,21 +107,32 @@ const { send } = useWebSocket(wsUrl, {
|
||||
};
|
||||
|
||||
viewerStore.setConnectionStatus("sending an sdp description");
|
||||
await peerConnection.setRemoteDescription(
|
||||
new RTCSessionDescription(message.sdp),
|
||||
);
|
||||
try {
|
||||
await peerConnection.setRemoteDescription(
|
||||
new RTCSessionDescription(message.sdp),
|
||||
);
|
||||
} catch (error) {
|
||||
console.error("Error setting remote description:", error);
|
||||
viewerStore.setConnectionStatus("failed to connect");
|
||||
return;
|
||||
}
|
||||
|
||||
viewerStore.setConnectionStatus("sending an answer");
|
||||
const answer = await peerConnection.createAnswer();
|
||||
await peerConnection.setLocalDescription(answer);
|
||||
try {
|
||||
const answer = await peerConnection.createAnswer();
|
||||
await peerConnection.setLocalDescription(answer);
|
||||
|
||||
send(
|
||||
JSON.stringify({
|
||||
event: "answer",
|
||||
targetId: message.senderId,
|
||||
sdp: answer,
|
||||
}),
|
||||
);
|
||||
send(
|
||||
JSON.stringify({
|
||||
event: "answer",
|
||||
targetId: message.senderId,
|
||||
sdp: answer,
|
||||
}),
|
||||
);
|
||||
} catch (error) {
|
||||
console.error("Error creating answer:", error);
|
||||
viewerStore.setConnectionStatus("failed to send answer");
|
||||
}
|
||||
}
|
||||
|
||||
if (message.event === "ice-candidate") {
|
||||
@@ -120,11 +143,21 @@ const { send } = useWebSocket(wsUrl, {
|
||||
viewerStore.setConnectionStatus(
|
||||
`got an ice candidate from remote peer (type: ${message.candidate.type})`,
|
||||
);
|
||||
await viewerStore.peerConnection.addIceCandidate(
|
||||
new RTCIceCandidate(message.candidate),
|
||||
);
|
||||
try {
|
||||
await viewerStore.peerConnection.addIceCandidate(
|
||||
new RTCIceCandidate(message.candidate),
|
||||
);
|
||||
} catch (error) {
|
||||
console.error("Error adding ICE candidate:", error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (message.event === "room-closed") {
|
||||
viewerStore.setConnectionStatus("room closed by host");
|
||||
cleanupViewing();
|
||||
isConnected.value = false;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@@ -145,4 +178,40 @@ watch(codeRef, (newCode) => {
|
||||
startWebRTCConnection();
|
||||
}
|
||||
});
|
||||
|
||||
function cleanupViewing() {
|
||||
// Close peer connection
|
||||
if (viewerStore.peerConnection) {
|
||||
viewerStore.peerConnection.close();
|
||||
viewerStore.setPeerConnection(null);
|
||||
}
|
||||
|
||||
// Clear video element
|
||||
if (videofeedRef.value) {
|
||||
videofeedRef.value.srcObject = null;
|
||||
}
|
||||
|
||||
// Reset connection status
|
||||
viewerStore.setConnectionStatus("disconnected");
|
||||
isConnected.value = false;
|
||||
}
|
||||
|
||||
// Cleanup on component unmount
|
||||
onBeforeUnmount(() => {
|
||||
cleanupViewing();
|
||||
closeWebSocket();
|
||||
});
|
||||
|
||||
// Cleanup on window/tab close
|
||||
onMounted(() => {
|
||||
const handleBeforeUnload = () => {
|
||||
cleanupViewing();
|
||||
};
|
||||
|
||||
window.addEventListener("beforeunload", handleBeforeUnload);
|
||||
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener("beforeunload", handleBeforeUnload);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -21,7 +21,7 @@ const videofeedRef = ref<HTMLVideoElement | null>(null);
|
||||
const localStream = ref<MediaStream | null>(null);
|
||||
const wsUrl = useWebSocketUrl();
|
||||
|
||||
const { send } = useWebSocket(wsUrl, {
|
||||
const { send, close: closeWebSocket } = useWebSocket(wsUrl, {
|
||||
autoReconnect: true,
|
||||
heartbeat: {
|
||||
message: JSON.stringify({ event: "ping" }),
|
||||
@@ -80,35 +80,110 @@ const { send } = useWebSocket(wsUrl, {
|
||||
if (message.event === "ice-candidate") {
|
||||
const pc = streamerStore.peerConnections[message.from];
|
||||
if (pc) {
|
||||
await pc.addIceCandidate(new RTCIceCandidate(message.candidate));
|
||||
try {
|
||||
await pc.addIceCandidate(new RTCIceCandidate(message.candidate));
|
||||
} catch (error) {
|
||||
console.error("Error adding ICE candidate:", error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (message.event === "answer") {
|
||||
const pc = streamerStore.peerConnections[message.from];
|
||||
if (pc) {
|
||||
await pc.setRemoteDescription(new RTCSessionDescription(message.sdp));
|
||||
try {
|
||||
await pc.setRemoteDescription(new RTCSessionDescription(message.sdp));
|
||||
} catch (error) {
|
||||
console.error("Error setting remote description:", error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (message.event === "viewer-left") {
|
||||
const pc = streamerStore.peerConnections[message.viewerId];
|
||||
if (pc) {
|
||||
pc.close();
|
||||
streamerStore.removePeerConnection(message.viewerId);
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
async function startScreenShare() {
|
||||
const stream = await navigator.mediaDevices.getDisplayMedia({
|
||||
video: true,
|
||||
audio: false,
|
||||
});
|
||||
try {
|
||||
const stream = await navigator.mediaDevices.getDisplayMedia({
|
||||
video: true,
|
||||
audio: false,
|
||||
});
|
||||
|
||||
localStream.value = stream;
|
||||
localStream.value = stream;
|
||||
|
||||
if (videofeedRef.value) {
|
||||
videofeedRef.value.srcObject = stream;
|
||||
if (videofeedRef.value) {
|
||||
videofeedRef.value.srcObject = stream;
|
||||
}
|
||||
|
||||
// Detect when user stops sharing via browser UI
|
||||
stream.getTracks().forEach((track) => {
|
||||
track.onended = () => {
|
||||
console.log("Screen sharing stopped by user");
|
||||
cleanupStreaming();
|
||||
};
|
||||
});
|
||||
|
||||
send(
|
||||
JSON.stringify({
|
||||
event: "create-room",
|
||||
}),
|
||||
);
|
||||
} catch (error) {
|
||||
console.error("Failed to start screen share:", error);
|
||||
// User cancelled or permission denied
|
||||
cleanupStreaming();
|
||||
}
|
||||
}
|
||||
|
||||
function cleanupStreaming() {
|
||||
// Stop all media tracks
|
||||
if (localStream.value) {
|
||||
localStream.value.getTracks().forEach((track) => {
|
||||
track.stop();
|
||||
});
|
||||
localStream.value = null;
|
||||
}
|
||||
|
||||
send(
|
||||
JSON.stringify({
|
||||
event: "create-room",
|
||||
}),
|
||||
);
|
||||
// Close all peer connections
|
||||
Object.values(streamerStore.peerConnections).forEach((pc) => {
|
||||
pc.close();
|
||||
});
|
||||
|
||||
// Clear peer connections from store
|
||||
streamerStore.clearPeerConnections();
|
||||
|
||||
// Clear video element
|
||||
if (videofeedRef.value) {
|
||||
videofeedRef.value.srcObject = null;
|
||||
}
|
||||
|
||||
// Clear room code
|
||||
streamerStore.setCode("");
|
||||
}
|
||||
|
||||
// Cleanup on component unmount
|
||||
onBeforeUnmount(() => {
|
||||
cleanupStreaming();
|
||||
closeWebSocket();
|
||||
});
|
||||
|
||||
// Cleanup on window/tab close
|
||||
onMounted(() => {
|
||||
const handleBeforeUnload = () => {
|
||||
cleanupStreaming();
|
||||
};
|
||||
|
||||
window.addEventListener("beforeunload", handleBeforeUnload);
|
||||
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener("beforeunload", handleBeforeUnload);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -13,6 +13,12 @@ export const useStreamerStore = defineStore("streamer", {
|
||||
addPeerConnection(id: string, pc: RTCPeerConnection) {
|
||||
this.peerConnections[id] = pc;
|
||||
},
|
||||
removePeerConnection(id: string) {
|
||||
delete this.peerConnections[id];
|
||||
},
|
||||
clearPeerConnections() {
|
||||
this.peerConnections = {};
|
||||
},
|
||||
setIceServers(iceServers: RTCIceServer[]) {
|
||||
this.iceServers = iceServers;
|
||||
},
|
||||
|
||||
@@ -10,7 +10,7 @@ export const useViewerStore = defineStore('viewer', {
|
||||
setCode(code: string) {
|
||||
this.code = code;
|
||||
},
|
||||
setPeerConnection(pc: RTCPeerConnection) {
|
||||
setPeerConnection(pc: RTCPeerConnection | null) {
|
||||
this.peerConnection = pc;
|
||||
},
|
||||
setConnectionStatus(status: string) {
|
||||
|
||||
Reference in New Issue
Block a user