99 lines
2.8 KiB
TypeScript
99 lines
2.8 KiB
TypeScript
import {
|
|
handleActiveSpeakerChange,
|
|
handleDisconnect,
|
|
handleLocalTrackUnpublished,
|
|
handleTrackSubscribed,
|
|
handleTrackUnsubscribed,
|
|
} from "helpers/liveKitEventHandler";
|
|
import { ConnectionQuality, Room, RoomEvent } from "livekit-client";
|
|
import { create } from "zustand";
|
|
|
|
let interval: NodeJS.Timeout;
|
|
|
|
type TalkState = {
|
|
isTalking: boolean;
|
|
state: "connecting" | "connected" | "disconnected" | "error";
|
|
message: string | null;
|
|
connectionQuality: ConnectionQuality;
|
|
remoteParticipants: number;
|
|
toggleTalking: () => void;
|
|
|
|
connect: (roomName: string) => void;
|
|
disconnect: () => void;
|
|
room: Room | null;
|
|
};
|
|
const getToken = async (roomName: string) => {
|
|
const response = await fetch(`/api/livekit/token?roomName=${roomName}`);
|
|
const data = await response.json();
|
|
return data.token;
|
|
};
|
|
|
|
export const useAudioStore = create<TalkState>((set, get) => ({
|
|
isTalking: false,
|
|
message: null,
|
|
state: "disconnected",
|
|
remoteParticipants: 0,
|
|
connectionQuality: ConnectionQuality.Unknown,
|
|
room: null,
|
|
toggleTalking: () => set((state) => ({ isTalking: !state.isTalking })),
|
|
connect: async (roomName) => {
|
|
set({ state: "connecting" });
|
|
console.log("Connecting to room: ", roomName);
|
|
try {
|
|
// Clean old room
|
|
const connectedRoom = get().room;
|
|
if (interval) clearInterval(interval);
|
|
if (connectedRoom) {
|
|
connectedRoom.disconnect();
|
|
connectedRoom.removeAllListeners();
|
|
}
|
|
|
|
const url = process.env.NEXT_PUBLIC_LIVEKIT_URL;
|
|
if (!url) return console.error("NEXT_PUBLIC_LIVEKIT_URL not set");
|
|
|
|
const token = await getToken(roomName);
|
|
if (!token) throw new Error("Fehlende Berechtigung");
|
|
const room = new Room({});
|
|
await room.prepareConnection(url, token);
|
|
room
|
|
// Connection events
|
|
.on(RoomEvent.Connected, () => {
|
|
set({ state: "connected", room, message: null });
|
|
})
|
|
.on(RoomEvent.Disconnected, () => {
|
|
set({ state: "disconnected" });
|
|
|
|
handleDisconnect();
|
|
})
|
|
.on(RoomEvent.ConnectionQualityChanged, (connectionQuality) =>
|
|
set({ connectionQuality }),
|
|
)
|
|
|
|
// Track events
|
|
.on(RoomEvent.TrackSubscribed, handleTrackSubscribed)
|
|
.on(RoomEvent.TrackUnsubscribed, handleTrackUnsubscribed)
|
|
.on(RoomEvent.ActiveSpeakersChanged, handleActiveSpeakerChange)
|
|
.on(RoomEvent.LocalTrackUnpublished, handleLocalTrackUnpublished);
|
|
await room.connect(url, token);
|
|
console.log(room);
|
|
set({ room });
|
|
interval = setInterval(() => {
|
|
set({
|
|
remoteParticipants:
|
|
room.numParticipants === 0 ? 0 : room.numParticipants - 1, // Unreliable and delayed
|
|
});
|
|
}, 500);
|
|
} catch (error: Error | unknown) {
|
|
console.error("Error occured: ", error);
|
|
if (error instanceof Error) {
|
|
set({ state: "error", message: error.message });
|
|
} else {
|
|
set({ state: "error", message: "Unknown error" });
|
|
}
|
|
}
|
|
},
|
|
disconnect: () => {
|
|
get().room?.disconnect();
|
|
},
|
|
}));
|