feat: Add deafen to pc, fix mobiel view, fix freeze on startup

This commit is contained in:
2026-06-05 15:27:06 +02:00
parent 35f52b0356
commit a675f12e61
85 changed files with 2499 additions and 519 deletions

View File

@@ -15,7 +15,13 @@
<button
type="button"
class="grid h-12 w-12 place-items-center rounded-full bg-secondary text-foreground transition-colors hover:bg-secondary/80 disabled:opacity-45"
class="grid h-12 w-12 place-items-center rounded-full transition-colors disabled:opacity-45"
[class.bg-secondary]="!muted()"
[class.text-foreground]="!muted()"
[class.hover:bg-secondary/80]="!muted()"
[class.bg-destructive/10]="muted()"
[class.text-destructive]="muted()"
[class.hover:bg-destructive/15]="muted()"
[disabled]="!connected()"
(click)="muteToggled.emit()"
[attr.aria-label]="muted() ? 'Unmute' : 'Mute'"
@@ -27,6 +33,26 @@
/>
</button>
<button
type="button"
class="grid h-12 w-12 place-items-center rounded-full transition-colors disabled:opacity-45"
[class.bg-secondary]="!deafened()"
[class.text-foreground]="!deafened()"
[class.hover:bg-secondary/80]="!deafened()"
[class.bg-destructive/10]="deafened()"
[class.text-destructive]="deafened()"
[class.hover:bg-destructive/15]="deafened()"
[disabled]="!connected()"
(click)="deafenToggled.emit()"
[attr.aria-label]="deafened() ? 'Undeafen' : 'Deafen'"
[title]="deafened() ? 'Undeafen' : 'Deafen'"
>
<ng-icon
name="lucideHeadphones"
class="h-5 w-5"
/>
</button>
@if (showSpeakerphoneButton()) {
<button
type="button"

View File

@@ -0,0 +1,34 @@
import { Injector, runInInjectionContext } from '@angular/core';
import {
describe,
expect,
it,
vi
} from 'vitest';
import { PrivateCallControlsComponent } from './private-call-controls.component';
function createComponent(): PrivateCallControlsComponent {
const injector = Injector.create({ providers: [PrivateCallControlsComponent] });
return runInInjectionContext(injector, () => injector.get(PrivateCallControlsComponent));
}
describe('PrivateCallControlsComponent', () => {
it('exposes deafened input and deafenToggled output', () => {
const component = createComponent();
expect(component.deafened).toBeDefined();
expect(component.deafenToggled).toBeDefined();
});
it('emits deafenToggled when the output is triggered', () => {
const component = createComponent();
const handler = vi.fn();
component.deafenToggled.subscribe(handler);
component.deafenToggled.emit();
expect(handler).toHaveBeenCalledTimes(1);
});
});

View File

@@ -5,6 +5,7 @@ import {
} from '@angular/core';
import { NgIcon, provideIcons } from '@ng-icons/core';
import {
lucideHeadphones,
lucideMic,
lucideMicOff,
lucideMonitor,
@@ -22,6 +23,7 @@ import {
imports: [NgIcon],
viewProviders: [
provideIcons({
lucideHeadphones,
lucideMic,
lucideMicOff,
lucideMonitor,
@@ -38,6 +40,7 @@ import {
export class PrivateCallControlsComponent {
readonly connected = input.required<boolean>();
readonly muted = input.required<boolean>();
readonly deafened = input.required<boolean>();
readonly cameraEnabled = input.required<boolean>();
readonly screenSharing = input.required<boolean>();
readonly showSpeakerphoneButton = input(false);
@@ -45,6 +48,7 @@ export class PrivateCallControlsComponent {
readonly joinRequested = output();
readonly muteToggled = output();
readonly deafenToggled = output();
readonly cameraToggled = output();
readonly screenShareToggled = output();
readonly speakerphoneToggled = output();

View File

@@ -196,12 +196,14 @@
class="mx-auto block w-full max-w-5xl"
[connected]="isConnected()"
[muted]="isMuted()"
[deafened]="isDeafened()"
[cameraEnabled]="isCameraEnabled()"
[screenSharing]="isScreenSharing()"
[showSpeakerphoneButton]="showSpeakerphoneButton()"
[speakerphoneEnabled]="speakerphoneEnabled()"
(joinRequested)="join()"
(muteToggled)="toggleMute()"
(deafenToggled)="toggleDeafen()"
(cameraToggled)="toggleCamera()"
(screenShareToggled)="toggleScreenShare()"
(speakerphoneToggled)="toggleSpeakerphone()"

View File

@@ -496,18 +496,27 @@ export class PrivateCallComponent {
return;
}
const voiceState = {
isConnected: this.isConnected(),
isMuted: this.isMuted(),
isDeafened: this.isDeafened(),
roomId: session.callId,
serverId: session.callId
};
this.store.dispatch(
UsersActions.updateVoiceState({
userId: user.id,
voiceState: {
isConnected: this.isConnected(),
isMuted: this.isMuted(),
isDeafened: this.isDeafened(),
roomId: session.callId,
serverId: session.callId
}
voiceState
})
);
this.voice.broadcastMessage({
type: 'voice-state',
oderId: user.oderId || user.id,
displayName: user.displayName || 'User',
voiceState
});
}
private remoteParticipantPeerIds(session: DirectCallSession, currentUserId: string): string[] {