fix voice not hearing each other

This commit is contained in:
2026-03-03 01:05:55 +01:00
parent 47304254f3
commit 50e7a66812
4 changed files with 361 additions and 97 deletions

View File

@@ -1,4 +1,13 @@
import { Component, inject, signal, OnInit, OnDestroy, ElementRef, ViewChild, computed } from '@angular/core';
import {
Component,
inject,
signal,
OnInit,
OnDestroy,
ElementRef,
ViewChild,
computed,
} from '@angular/core';
import { CommonModule } from '@angular/common';
import { Store } from '@ngrx/store';
import { NgIcon, provideIcons } from '@ng-icons/core';
@@ -75,7 +84,7 @@ export class VoiceControlsComponent implements OnInit, OnDestroy {
inputVolume = signal(100);
outputVolume = signal(100);
audioBitrate = signal(96);
latencyProfile = signal<'low'|'balanced'|'high'>('balanced');
latencyProfile = signal<'low' | 'balanced' | 'high'>('balanced');
includeSystemAudio = signal(false);
private voiceConnectedSubscription: Subscription | null = null;
@@ -91,7 +100,7 @@ export class VoiceControlsComponent implements OnInit, OnDestroy {
this.remoteStreamSubscription = this.webrtcService.onRemoteStream.subscribe(
({ peerId, stream }) => {
this.playRemoteAudio(peerId, stream);
}
},
);
// Subscribe to voice connected event to play pending streams and ensure all remote audio is set up
@@ -208,9 +217,10 @@ export class VoiceControlsComponent implements OnInit, OnDestroy {
}
// Play the audio
audio.play().then(() => {
}).catch((error) => {
});
audio
.play()
.then(() => {})
.catch((error) => {});
this.remoteAudioElements.set(peerId, audio);
}
@@ -224,15 +234,14 @@ export class VoiceControlsComponent implements OnInit, OnDestroy {
this.inputDevices.set(
devices
.filter((device) => device.kind === 'audioinput')
.map((device) => ({ deviceId: device.deviceId, label: device.label }))
.map((device) => ({ deviceId: device.deviceId, label: device.label })),
);
this.outputDevices.set(
devices
.filter((device) => device.kind === 'audiooutput')
.map((device) => ({ deviceId: device.deviceId, label: device.label }))
.map((device) => ({ deviceId: device.deviceId, label: device.label })),
);
} catch (error) {
}
} catch (error) {}
}
async connect(): Promise<void> {
@@ -264,8 +273,10 @@ export class VoiceControlsComponent implements OnInit, OnDestroy {
}
// Start voice heartbeat to broadcast presence every 5 seconds
const roomId = this.currentUser()?.voiceState?.roomId;
this.webrtcService.startVoiceHeartbeat(roomId);
const room = this.currentRoom();
const roomId = this.currentUser()?.voiceState?.roomId || room?.id;
const serverId = room?.id;
this.webrtcService.startVoiceHeartbeat(roomId, serverId);
// Broadcast voice state to other users
this.webrtcService.broadcastMessage({
@@ -277,6 +288,7 @@ export class VoiceControlsComponent implements OnInit, OnDestroy {
isMuted: this.isMuted(),
isDeafened: this.isDeafened(),
roomId,
serverId,
},
});
@@ -288,16 +300,14 @@ export class VoiceControlsComponent implements OnInit, OnDestroy {
// Persist settings after successful connection
this.saveSettings();
} catch (error) {
}
} catch (error) {}
}
// Retry connection when there's a connection error
async retryConnection(): Promise<void> {
try {
await this.webrtcService.ensureSignalingConnected(10000);
} catch (_error) {
}
} catch (_error) {}
}
disconnect(): void {
@@ -313,6 +323,7 @@ export class VoiceControlsComponent implements OnInit, OnDestroy {
isConnected: false,
isMuted: false,
isDeafened: false,
serverId: this.currentRoom()?.id,
},
});
@@ -340,10 +351,18 @@ export class VoiceControlsComponent implements OnInit, OnDestroy {
const user = this.currentUser();
if (user?.id) {
this.store.dispatch(UsersActions.updateVoiceState({
userId: user.id,
voiceState: { isConnected: false, isMuted: false, isDeafened: false, roomId: undefined, serverId: undefined }
}));
this.store.dispatch(
UsersActions.updateVoiceState({
userId: user.id,
voiceState: {
isConnected: false,
isMuted: false,
isDeafened: false,
roomId: undefined,
serverId: undefined,
},
}),
);
}
// End voice session for floating controls
@@ -407,8 +426,7 @@ export class VoiceControlsComponent implements OnInit, OnDestroy {
try {
await this.webrtcService.startScreenShare(this.includeSystemAudio());
this.isScreenSharing.set(true);
} catch (error) {
}
} catch (error) {}
}
}
@@ -458,7 +476,7 @@ export class VoiceControlsComponent implements OnInit, OnDestroy {
onLatencyProfileChange(event: Event): void {
const select = event.target as HTMLSelectElement;
const profile = select.value as 'low'|'balanced'|'high';
const profile = select.value as 'low' | 'balanced' | 'high';
this.latencyProfile.set(profile);
this.webrtcService.setLatencyProfile(profile);
this.saveSettings();
@@ -488,7 +506,7 @@ export class VoiceControlsComponent implements OnInit, OnDestroy {
inputVolume?: number;
outputVolume?: number;
audioBitrate?: number;
latencyProfile?: 'low'|'balanced'|'high';
latencyProfile?: 'low' | 'balanced' | 'high';
includeSystemAudio?: boolean;
};
if (settings.inputDevice) this.selectedInputDevice.set(settings.inputDevice);
@@ -497,7 +515,8 @@ export class VoiceControlsComponent implements OnInit, OnDestroy {
if (typeof settings.outputVolume === 'number') this.outputVolume.set(settings.outputVolume);
if (typeof settings.audioBitrate === 'number') this.audioBitrate.set(settings.audioBitrate);
if (settings.latencyProfile) this.latencyProfile.set(settings.latencyProfile);
if (typeof settings.includeSystemAudio === 'boolean') this.includeSystemAudio.set(settings.includeSystemAudio);
if (typeof settings.includeSystemAudio === 'boolean')
this.includeSystemAudio.set(settings.includeSystemAudio);
} catch {}
}
@@ -537,7 +556,8 @@ export class VoiceControlsComponent implements OnInit, OnDestroy {
}
getMuteButtonClass(): string {
const base = 'w-10 h-10 inline-flex items-center justify-center rounded-full transition-colors disabled:opacity-50 disabled:cursor-not-allowed';
const base =
'w-10 h-10 inline-flex items-center justify-center rounded-full transition-colors disabled:opacity-50 disabled:cursor-not-allowed';
if (this.isMuted()) {
return `${base} bg-destructive/20 text-destructive hover:bg-destructive/30`;
}
@@ -545,7 +565,8 @@ export class VoiceControlsComponent implements OnInit, OnDestroy {
}
getDeafenButtonClass(): string {
const base = 'w-10 h-10 inline-flex items-center justify-center rounded-full transition-colors disabled:opacity-50 disabled:cursor-not-allowed';
const base =
'w-10 h-10 inline-flex items-center justify-center rounded-full transition-colors disabled:opacity-50 disabled:cursor-not-allowed';
if (this.isDeafened()) {
return `${base} bg-destructive/20 text-destructive hover:bg-destructive/30`;
}
@@ -553,7 +574,8 @@ export class VoiceControlsComponent implements OnInit, OnDestroy {
}
getScreenShareButtonClass(): string {
const base = 'w-10 h-10 inline-flex items-center justify-center rounded-full transition-colors disabled:opacity-50 disabled:cursor-not-allowed';
const base =
'w-10 h-10 inline-flex items-center justify-center rounded-full transition-colors disabled:opacity-50 disabled:cursor-not-allowed';
if (this.isScreenSharing()) {
return `${base} bg-primary/20 text-primary hover:bg-primary/30`;
}