mirror of
https://github.com/J3vb/OwnCord.git
synced 2026-09-03 03:50:00 +03:00
fix: voice session cleanup on ICE close and connection failure
- Server: handle ICEConnectionStateClosed in setupICEMonitor to clean up phantom participants when client PC is destroyed - Server: skip TURN config when turn_secret is empty (suppresses noisy "password is empty" errors) - Client: voiceSession.leaveVoice() now sends voice_leave to server by default, fixing the case where WebRTC failure triggers local cleanup but server never learns the user left - Client: explicit leave paths (UI button, logout, beforeunload) pass sendWs=false to avoid double-sending voice_leave
This commit is contained in:
@@ -220,8 +220,17 @@ export async function joinVoice(
|
||||
}
|
||||
}
|
||||
|
||||
/** Leave the current voice session and clean up all resources. */
|
||||
export function leaveVoice(): void {
|
||||
/**
|
||||
* Leave the current voice session and clean up all resources.
|
||||
* If sendWs is true (default), also notifies the server via voice_leave.
|
||||
* Pass sendWs=false when the server already knows (e.g. explicit UI leave
|
||||
* that sends voice_leave separately).
|
||||
*/
|
||||
export function leaveVoice(sendWs = true): void {
|
||||
// Notify server so it cleans up our voice state
|
||||
if (sendWs && ws !== null) {
|
||||
ws.send({ type: "voice_leave", payload: {} });
|
||||
}
|
||||
// Stop all local media tracks
|
||||
if (localStream !== null) {
|
||||
for (const track of localStream.getTracks()) {
|
||||
|
||||
@@ -293,7 +293,7 @@ authStore.subscribe((state) => {
|
||||
// Leave voice channel before disconnecting so other clients see it immediately
|
||||
const voice = voiceStore.getState();
|
||||
if (voice.currentChannelId !== null) {
|
||||
voiceSessionLeave();
|
||||
voiceSessionLeave(false); // false: we send voice_leave below
|
||||
ws.send({ type: "voice_leave", payload: {} });
|
||||
leaveVoiceChannel();
|
||||
}
|
||||
@@ -313,7 +313,7 @@ authStore.subscribe((state) => {
|
||||
window.addEventListener("beforeunload", () => {
|
||||
const voice = voiceStore.getState();
|
||||
if (voice.currentChannelId !== null) {
|
||||
voiceSessionLeave();
|
||||
voiceSessionLeave(false); // false: we send voice_leave below
|
||||
ws.send({ type: "voice_leave", payload: {} });
|
||||
}
|
||||
});
|
||||
|
||||
@@ -375,7 +375,7 @@ export function createMainPage(options: MainPageOptions): MountableComponent {
|
||||
},
|
||||
onVoiceLeave: () => {
|
||||
log.info("Leaving voice channel");
|
||||
voiceSessionLeave();
|
||||
voiceSessionLeave(false); // false: we send voice_leave below
|
||||
leaveVoiceChannel();
|
||||
ws.send({ type: "voice_leave", payload: {} });
|
||||
},
|
||||
@@ -415,7 +415,7 @@ export function createMainPage(options: MainPageOptions): MountableComponent {
|
||||
onDisconnect: () => {
|
||||
if (voiceStore.getState().currentChannelId === null) return;
|
||||
log.info("Leaving voice channel (widget disconnect)");
|
||||
voiceSessionLeave();
|
||||
voiceSessionLeave(false); // false: we send voice_leave below
|
||||
leaveVoiceChannel();
|
||||
ws.send({ type: "voice_leave", payload: {} });
|
||||
},
|
||||
|
||||
+2
-2
@@ -80,8 +80,8 @@ func (s *SFU) NewPeerConnection() (*webrtc.PeerConnection, error) {
|
||||
})
|
||||
}
|
||||
|
||||
// Add TURN server if enabled.
|
||||
if s.config.TURNEnabled && s.config.TURNPort > 0 {
|
||||
// Add TURN server if enabled and secret is configured.
|
||||
if s.config.TURNEnabled && s.config.TURNPort > 0 && s.config.TURNSecret != "" {
|
||||
pcConfig.ICEServers = append(pcConfig.ICEServers, webrtc.ICEServer{
|
||||
URLs: []string{"turn:localhost:" + strconv.Itoa(s.config.TURNPort)},
|
||||
Username: "owncord",
|
||||
|
||||
@@ -40,6 +40,11 @@ func (h *Hub) setupICEMonitor(c *Client, channelID int64) {
|
||||
case webrtc.ICEConnectionStateFailed:
|
||||
slog.Warn("ICE connection failed, cleaning up voice", "user_id", c.userID, "channel_id", channelID)
|
||||
h.handleVoiceLeave(c)
|
||||
case webrtc.ICEConnectionStateClosed:
|
||||
// Closed means the PC was shut down (client destroyed it).
|
||||
// Clean up server-side voice state as a safety net.
|
||||
slog.Info("ICE connection closed, cleaning up voice", "user_id", c.userID, "channel_id", channelID)
|
||||
h.handleVoiceLeave(c)
|
||||
case webrtc.ICEConnectionStateDisconnected:
|
||||
// Disconnected is transient — ICE may recover.
|
||||
// Log but don't clean up immediately.
|
||||
|
||||
Reference in New Issue
Block a user