fix webrtc
This commit is contained in:
@@ -41,10 +41,10 @@
|
||||
return `${bps.toFixed(0)} bps`;
|
||||
};
|
||||
|
||||
function handleContextMenu(e: MouseEvent, vsIdentity: any) {
|
||||
function handleContextMenu(e: MouseEvent, targetIdentity: any) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
const user = chat.users.find((u) => u.identity.isEqual(vsIdentity));
|
||||
const user = chat.users.find((u) => u.identity.isEqual(targetIdentity));
|
||||
if (user) {
|
||||
chat.userContextMenu = { x: e.clientX, y: e.clientY, user };
|
||||
}
|
||||
@@ -144,9 +144,10 @@
|
||||
</span>
|
||||
{:else if s.isMuted}
|
||||
<span class="voice-indicator-icon" title="Muted"><i class="fas fa-microphone-slash"></i></span>
|
||||
{#if isLocalUserInThisChannel}
|
||||
<div class="status-dot {voiceStatusColor}"></div>
|
||||
{/if}
|
||||
|
||||
{#if isLocalUserInThisChannel && (s.isDeafened || s.isMuted)}
|
||||
<div class="status-dot {voiceStatusColor}"></div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -87,9 +87,13 @@ export class ChannelAudioWebRTCService {
|
||||
});
|
||||
|
||||
// Lifecycle Mesh Management
|
||||
let lastChannelId: bigint | undefined = undefined;
|
||||
$effect(() => {
|
||||
if (!this.connectedChannelId || !this.identity) {
|
||||
console.log(`[WebRTC][voice] Cleaning up channel state`);
|
||||
const currentChannelId = this.connectedChannelId;
|
||||
const currentIdentity = this.identity;
|
||||
|
||||
if (!currentChannelId || !currentIdentity) {
|
||||
console.log(`[WebRTC][voice] Cleaning up channel state (Channel: ${currentChannelId}, Identity: ${currentIdentity?.toHexString().substring(0,8)})`);
|
||||
this.peerManager.peers.forEach((_, id) =>
|
||||
this.peerManager.closePeer(id),
|
||||
);
|
||||
@@ -97,15 +101,27 @@ export class ChannelAudioWebRTCService {
|
||||
this.makingOffer.clear();
|
||||
this.ignoreOffer.clear();
|
||||
this.signalingQueue.clear();
|
||||
lastChannelId = undefined;
|
||||
return;
|
||||
}
|
||||
|
||||
// If we switched channels, clear state for the new connection mesh
|
||||
if (lastChannelId !== undefined && lastChannelId !== currentChannelId) {
|
||||
console.log(`[WebRTC][voice] Channel switched ${lastChannelId} -> ${currentChannelId}, resetting mesh state`);
|
||||
this.peerManager.peers.forEach((_, id) => this.peerManager.closePeer(id));
|
||||
this.processedSignals.clear();
|
||||
this.makingOffer.clear();
|
||||
this.ignoreOffer.clear();
|
||||
this.signalingQueue.clear();
|
||||
}
|
||||
lastChannelId = currentChannelId;
|
||||
|
||||
const peersToConnect = new Set(
|
||||
this.userStates
|
||||
.filter(
|
||||
(s) =>
|
||||
s.channelId === this.connectedChannelId &&
|
||||
!s.identity.isEqual(this.identity!),
|
||||
s.channelId === currentChannelId &&
|
||||
!s.identity.isEqual(currentIdentity),
|
||||
)
|
||||
.map((s) => s.identity.toHexString()),
|
||||
);
|
||||
@@ -132,19 +148,26 @@ export class ChannelAudioWebRTCService {
|
||||
|
||||
// Signaling Processors
|
||||
$effect(() => {
|
||||
if (!this.connectedChannelId || !this.identity) return;
|
||||
const currentChannelId = this.connectedChannelId;
|
||||
const currentIdentity = this.identity;
|
||||
if (!currentChannelId || !currentIdentity) return;
|
||||
|
||||
const mySignals = this.signals.filter(
|
||||
(s) =>
|
||||
s.channelId === this.connectedChannelId &&
|
||||
s.receiver.isEqual(this.identity!) &&
|
||||
s.channelId === currentChannelId &&
|
||||
s.receiver.isEqual(currentIdentity) &&
|
||||
s.mediaType.tag === "Voice"
|
||||
);
|
||||
|
||||
if (mySignals.length > 0) {
|
||||
console.log(`[WebRTC][voice] Found ${mySignals.length} signals for channel ${currentChannelId}`);
|
||||
}
|
||||
|
||||
for (const signal of mySignals) {
|
||||
if (this.processedSignals.has(signal.id)) continue;
|
||||
this.processedSignals.add(signal.id);
|
||||
|
||||
console.log(`[WebRTC][voice] Processing ${signal.signalKind.tag} from ${signal.sender.toHexString().substring(0,8)} (Signal ID: ${signal.id})`);
|
||||
switch (signal.signalKind.tag) {
|
||||
case "Offer":
|
||||
this.handleOffer(signal);
|
||||
@@ -203,6 +226,7 @@ export class ChannelAudioWebRTCService {
|
||||
try {
|
||||
this.makingOffer.set(peerIdHex, true);
|
||||
await pc.setLocalDescription();
|
||||
console.log(`[WebRTC][voice] Sending Offer to ${peerIdHex.substring(0,8)}`);
|
||||
this.#sendSignal({
|
||||
receiver: Identity.fromString(peerIdHex),
|
||||
signalKind: { tag: "Offer" },
|
||||
@@ -218,6 +242,7 @@ export class ChannelAudioWebRTCService {
|
||||
|
||||
onIceCandidate(peerIdHex: string, candidate: RTCIceCandidate) {
|
||||
if (this.connectedChannelId) {
|
||||
console.log(`[WebRTC][voice] Sending ICE candidate to ${peerIdHex.substring(0,8)}`);
|
||||
this.#sendSignal({
|
||||
receiver: Identity.fromString(peerIdHex),
|
||||
signalKind: { tag: "IceCandidate" },
|
||||
@@ -247,6 +272,7 @@ export class ChannelAudioWebRTCService {
|
||||
);
|
||||
const answer = await pc.createAnswer();
|
||||
await pc.setLocalDescription(answer);
|
||||
console.log(`[WebRTC][voice] Sending Answer to ${peerIdHex.substring(0,8)}`);
|
||||
this.#sendSignal({
|
||||
receiver: signal.sender,
|
||||
signalKind: { tag: "Answer" },
|
||||
@@ -266,6 +292,7 @@ export class ChannelAudioWebRTCService {
|
||||
|
||||
handleAnswer(signal: Types.WebRtcSignal) {
|
||||
const peerIdHex = signal.sender.toHexString();
|
||||
console.log(`[WebRTC][voice] Received Answer from ${peerIdHex.substring(0,8)}`);
|
||||
this.enqueueSignalingTask(peerIdHex, async () => {
|
||||
const peer = this.peerManager.getPeer(peerIdHex);
|
||||
if (!peer) return;
|
||||
@@ -285,6 +312,7 @@ export class ChannelAudioWebRTCService {
|
||||
|
||||
handleIceCandidate(signal: Types.WebRtcSignal) {
|
||||
const peerIdHex = signal.sender.toHexString();
|
||||
console.log(`[WebRTC][voice] Received ICE candidate from ${peerIdHex.substring(0,8)}`);
|
||||
this.enqueueSignalingTask(peerIdHex, async () => {
|
||||
const pc = this.peerManager.createPeerConnection(peerIdHex);
|
||||
if (!pc) return;
|
||||
|
||||
@@ -82,9 +82,13 @@ export class ScreenSharingWebRTCService {
|
||||
});
|
||||
|
||||
// Lifecycle Mesh Management
|
||||
let lastChannelId: bigint | undefined = undefined;
|
||||
$effect(() => {
|
||||
if (!this.connectedChannelId || !this.identity) {
|
||||
console.log(`[WebRTC][screen] Cleaning up screen state`);
|
||||
const currentChannelId = this.connectedChannelId;
|
||||
const currentIdentity = this.identity;
|
||||
|
||||
if (!currentChannelId || !currentIdentity) {
|
||||
console.log(`[WebRTC][screen] Cleaning up screen state (Channel: ${currentChannelId}, Identity: ${currentIdentity?.toHexString().substring(0,8)})`);
|
||||
this.peerManager.peers.forEach((_, id) =>
|
||||
this.peerManager.closePeer(id),
|
||||
);
|
||||
@@ -92,18 +96,30 @@ export class ScreenSharingWebRTCService {
|
||||
this.makingOffer.clear();
|
||||
this.ignoreOffer.clear();
|
||||
this.signalingQueue.clear();
|
||||
lastChannelId = undefined;
|
||||
return;
|
||||
}
|
||||
|
||||
// If we switched channels, clear state for the new connection mesh
|
||||
if (lastChannelId !== undefined && lastChannelId !== currentChannelId) {
|
||||
console.log(`[WebRTC][screen] Channel switched ${lastChannelId} -> ${currentChannelId}, resetting mesh state`);
|
||||
this.peerManager.peers.forEach((_, id) => this.peerManager.closePeer(id));
|
||||
this.processedSignals.clear();
|
||||
this.makingOffer.clear();
|
||||
this.ignoreOffer.clear();
|
||||
this.signalingQueue.clear();
|
||||
}
|
||||
lastChannelId = currentChannelId;
|
||||
|
||||
const screenPeersToConnect = new Set<string>();
|
||||
this.userStates.forEach((s) => {
|
||||
if (s.channelId === this.connectedChannelId) {
|
||||
if (s.channelId === currentChannelId) {
|
||||
// If I am watching this user
|
||||
if (s.identity.isEqual(this.identity!)) {
|
||||
if (s.identity.isEqual(currentIdentity)) {
|
||||
if (s.watching) screenPeersToConnect.add(s.watching.toHexString());
|
||||
}
|
||||
// If this user is watching me
|
||||
if (s.watching?.isEqual(this.identity!)) {
|
||||
if (s.watching?.isEqual(currentIdentity)) {
|
||||
screenPeersToConnect.add(s.identity.toHexString());
|
||||
}
|
||||
}
|
||||
@@ -111,7 +127,7 @@ export class ScreenSharingWebRTCService {
|
||||
|
||||
screenPeersToConnect.forEach((id) => {
|
||||
if (!this.peerManager.peers.has(id)) {
|
||||
console.log(`[WebRTC][screen] Connecting to watched peer ${id}`);
|
||||
console.log(`[WebRTC][screen] Connecting to watched peer ${id.substring(0,8)}`);
|
||||
this.peerManager.createPeerConnection(id, [
|
||||
this.localScreenStream?.getVideoTracks()[0] || null,
|
||||
this.localScreenStream?.getAudioTracks()[0] || null,
|
||||
@@ -121,7 +137,7 @@ export class ScreenSharingWebRTCService {
|
||||
|
||||
this.peerManager.peers.forEach((_, id) => {
|
||||
if (!screenPeersToConnect.has(id)) {
|
||||
console.log(`[WebRTC][screen] Peer ${id} no longer watched, closing`);
|
||||
console.log(`[WebRTC][screen] Peer ${id.substring(0,8)} no longer watched, closing`);
|
||||
this.peerManager.closePeer(id);
|
||||
this.makingOffer.delete(id);
|
||||
this.ignoreOffer.delete(id);
|
||||
@@ -132,19 +148,26 @@ export class ScreenSharingWebRTCService {
|
||||
|
||||
// Signaling Processors
|
||||
$effect(() => {
|
||||
if (!this.connectedChannelId || !this.identity) return;
|
||||
const currentChannelId = this.connectedChannelId;
|
||||
const currentIdentity = this.identity;
|
||||
if (!currentChannelId || !currentIdentity) return;
|
||||
|
||||
const mySignals = this.signals.filter(
|
||||
(s) =>
|
||||
s.channelId === this.connectedChannelId &&
|
||||
s.receiver.isEqual(this.identity!) &&
|
||||
s.channelId === currentChannelId &&
|
||||
s.receiver.isEqual(currentIdentity) &&
|
||||
s.mediaType.tag === "Screen"
|
||||
);
|
||||
|
||||
if (mySignals.length > 0) {
|
||||
console.log(`[WebRTC][screen] Found ${mySignals.length} signals for channel ${currentChannelId}`);
|
||||
}
|
||||
|
||||
for (const signal of mySignals) {
|
||||
if (this.processedSignals.has(signal.id)) continue;
|
||||
this.processedSignals.add(signal.id);
|
||||
|
||||
console.log(`[WebRTC][screen] Processing ${signal.signalKind.tag} from ${signal.sender.toHexString().substring(0,8)} (Signal ID: ${signal.id})`);
|
||||
switch (signal.signalKind.tag) {
|
||||
case "Offer":
|
||||
this.handleOffer(signal);
|
||||
@@ -203,6 +226,7 @@ export class ScreenSharingWebRTCService {
|
||||
try {
|
||||
this.makingOffer.set(peerIdHex, true);
|
||||
await pc.setLocalDescription();
|
||||
console.log(`[WebRTC][screen] Sending Offer to ${peerIdHex.substring(0,8)}`);
|
||||
this.#sendSignal({
|
||||
receiver: Identity.fromString(peerIdHex),
|
||||
signalKind: { tag: "Offer" },
|
||||
@@ -218,6 +242,7 @@ export class ScreenSharingWebRTCService {
|
||||
|
||||
onIceCandidate(peerIdHex: string, candidate: RTCIceCandidate) {
|
||||
if (this.connectedChannelId) {
|
||||
console.log(`[WebRTC][screen] Sending ICE candidate to ${peerIdHex.substring(0,8)}`);
|
||||
this.#sendSignal({
|
||||
receiver: Identity.fromString(peerIdHex),
|
||||
signalKind: { tag: "IceCandidate" },
|
||||
@@ -230,6 +255,7 @@ export class ScreenSharingWebRTCService {
|
||||
|
||||
handleOffer(signal: Types.WebRtcSignal) {
|
||||
const peerIdHex = signal.sender.toHexString();
|
||||
console.log(`[WebRTC][screen] Received Offer from ${peerIdHex.substring(0,8)}`);
|
||||
this.enqueueSignalingTask(peerIdHex, async () => {
|
||||
const pc = this.peerManager.createPeerConnection(peerIdHex);
|
||||
if (!pc) return;
|
||||
@@ -247,6 +273,7 @@ export class ScreenSharingWebRTCService {
|
||||
);
|
||||
const answer = await pc.createAnswer();
|
||||
await pc.setLocalDescription(answer);
|
||||
console.log(`[WebRTC][screen] Sending Answer to ${peerIdHex.substring(0,8)}`);
|
||||
this.#sendSignal({
|
||||
receiver: signal.sender,
|
||||
signalKind: { tag: "Answer" },
|
||||
@@ -266,6 +293,7 @@ export class ScreenSharingWebRTCService {
|
||||
|
||||
handleAnswer(signal: Types.WebRtcSignal) {
|
||||
const peerIdHex = signal.sender.toHexString();
|
||||
console.log(`[WebRTC][screen] Received Answer from ${peerIdHex.substring(0,8)}`);
|
||||
this.enqueueSignalingTask(peerIdHex, async () => {
|
||||
const peer = this.peerManager.getPeer(peerIdHex);
|
||||
if (!peer) return;
|
||||
@@ -285,6 +313,7 @@ export class ScreenSharingWebRTCService {
|
||||
|
||||
handleIceCandidate(signal: Types.WebRtcSignal) {
|
||||
const peerIdHex = signal.sender.toHexString();
|
||||
console.log(`[WebRTC][screen] Received ICE candidate from ${peerIdHex.substring(0,8)}`);
|
||||
this.enqueueSignalingTask(peerIdHex, async () => {
|
||||
const pc = this.peerManager.createPeerConnection(peerIdHex);
|
||||
if (!pc) return;
|
||||
|
||||
@@ -67,6 +67,10 @@ export class WebRTCService {
|
||||
|
||||
this.localMedia = new LocalMediaService(connectedChannelId);
|
||||
|
||||
$effect(() => {
|
||||
this.localMedia.connectedChannelId = this.connectedChannelId;
|
||||
});
|
||||
|
||||
// Pass localMedia's stream and deafen state to voice
|
||||
this.voice = new ChannelAudioWebRTCService(
|
||||
identity,
|
||||
@@ -81,6 +85,13 @@ export class WebRTCService {
|
||||
this.localMedia.localScreenStream,
|
||||
);
|
||||
|
||||
$effect(() => {
|
||||
this.voice.connectedChannelId = this.connectedChannelId;
|
||||
this.screen.connectedChannelId = this.connectedChannelId;
|
||||
this.voice.localStream = this.localMedia.localStream;
|
||||
this.screen.localScreenStream = this.localMedia.localScreenStream;
|
||||
});
|
||||
|
||||
// Sound for streams I am watching
|
||||
let lastWatched = new Set<string>();
|
||||
$effect(() => {
|
||||
|
||||
Reference in New Issue
Block a user