added Sounds für Livekit
This commit is contained in:
@@ -21,11 +21,9 @@ import { ROOMS } from "_data/livekitRooms";
|
|||||||
import { useDispatchConnectionStore } from "_store/dispatch/connectionStore";
|
import { useDispatchConnectionStore } from "_store/dispatch/connectionStore";
|
||||||
import { useSession } from "next-auth/react";
|
import { useSession } from "next-auth/react";
|
||||||
import { dispatchSocket } from "dispatch/socket";
|
import { dispatchSocket } from "dispatch/socket";
|
||||||
|
import { useSounds } from "_components/Audio/useSounds";
|
||||||
|
|
||||||
export const Audio = () => {
|
export const Audio = () => {
|
||||||
const connection = usePilotConnectionStore();
|
|
||||||
const [showSource, setShowSource] = useState(false);
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
speakingParticipants,
|
speakingParticipants,
|
||||||
isTalking,
|
isTalking,
|
||||||
@@ -40,6 +38,11 @@ export const Audio = () => {
|
|||||||
removeMessage,
|
removeMessage,
|
||||||
} = useAudioStore();
|
} = useAudioStore();
|
||||||
const [selectedRoom, setSelectedRoom] = useState<string>("LST_01");
|
const [selectedRoom, setSelectedRoom] = useState<string>("LST_01");
|
||||||
|
useSounds({
|
||||||
|
isReceiving: speakingParticipants.length > 0,
|
||||||
|
isTransmitting: isTalking,
|
||||||
|
unpausedTracks: speakingParticipants,
|
||||||
|
});
|
||||||
|
|
||||||
const { selectedStation, status: pilotState } = usePilotConnectionStore((state) => state);
|
const { selectedStation, status: pilotState } = usePilotConnectionStore((state) => state);
|
||||||
|
|
||||||
90
apps/dispatch/app/_components/Audio/useSounds.ts
Normal file
90
apps/dispatch/app/_components/Audio/useSounds.ts
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
"use client";
|
||||||
|
import { useDebounce } from "_helpers/useDebounce";
|
||||||
|
import { useEffect, useRef, useState } from "react";
|
||||||
|
|
||||||
|
export const useSounds = ({
|
||||||
|
isReceiving,
|
||||||
|
isTransmitting,
|
||||||
|
unpausedTracks,
|
||||||
|
}: {
|
||||||
|
isReceiving: boolean;
|
||||||
|
isTransmitting: boolean;
|
||||||
|
unpausedTracks: unknown[];
|
||||||
|
}) => {
|
||||||
|
// Sounds as refs
|
||||||
|
const connectionStart = useRef<HTMLAudioElement | null>(null);
|
||||||
|
const connectionEnd = useRef<HTMLAudioElement | null>(null);
|
||||||
|
const ownCallStarted = useRef<HTMLAudioElement | null>(null);
|
||||||
|
const foreignCallStop = useRef<HTMLAudioElement | null>(null);
|
||||||
|
const foreignCallBlocked = useRef<HTMLAudioElement | null>(null);
|
||||||
|
const callToLong = useRef<HTMLAudioElement | null>(null);
|
||||||
|
const adminCall = useRef<HTMLAudioElement | null>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!window) return;
|
||||||
|
connectionStart.current = new Audio("/sounds/connection_started_sepura.mp3");
|
||||||
|
connectionEnd.current = new Audio("/sounds/connection_stoped_sepura.mp3");
|
||||||
|
ownCallStarted.current = new Audio("/sounds/call_end_sepura.wav");
|
||||||
|
foreignCallStop.current = new Audio("/sounds/call_end_sepura.wav");
|
||||||
|
foreignCallBlocked.current = new Audio("/sounds/call_blocked_sepura.wav");
|
||||||
|
callToLong.current = new Audio("/sounds/call_to_long.wav");
|
||||||
|
adminCall.current = new Audio("/sounds/call_interrupted_by_admin.mp3");
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const [soundConnectionStarted, setSoundsConnectionStarted] = useState(false);
|
||||||
|
|
||||||
|
useDebounce(
|
||||||
|
() => {
|
||||||
|
if (!isReceiving && !isTransmitting && soundConnectionStarted) {
|
||||||
|
setSoundsConnectionStarted(false);
|
||||||
|
connectionEnd.current!.currentTime = 0;
|
||||||
|
connectionEnd.current!.play();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
3000,
|
||||||
|
[unpausedTracks, isReceiving, isTransmitting],
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if ((isReceiving || isTransmitting) && !soundConnectionStarted) {
|
||||||
|
setSoundsConnectionStarted(true);
|
||||||
|
connectionStart.current!.currentTime = 0;
|
||||||
|
connectionStart.current!.play();
|
||||||
|
ownCallStarted.current!.pause();
|
||||||
|
}
|
||||||
|
}, [isReceiving, isTransmitting, soundConnectionStarted]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isTransmitting && connectionStart.current!.paused) {
|
||||||
|
ownCallStarted.current!.volume = 0.2;
|
||||||
|
ownCallStarted.current!.currentTime = 0;
|
||||||
|
ownCallStarted.current!.play();
|
||||||
|
}
|
||||||
|
}, [isTransmitting]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!isReceiving) {
|
||||||
|
foreignCallStop.current!.volume = 0.2;
|
||||||
|
foreignCallStop.current!.currentTime = 0;
|
||||||
|
foreignCallStop.current!.play().catch(() => {});
|
||||||
|
}
|
||||||
|
}, [isReceiving]);
|
||||||
|
|
||||||
|
// Hotmic warning after 30 seconds
|
||||||
|
useEffect(() => {
|
||||||
|
if (isTransmitting) {
|
||||||
|
const timeout = setTimeout(() => {
|
||||||
|
if (isTransmitting) {
|
||||||
|
callToLong.current!.loop = true;
|
||||||
|
callToLong.current!.currentTime = 0;
|
||||||
|
callToLong.current!.volume = 1;
|
||||||
|
callToLong.current!.play();
|
||||||
|
}
|
||||||
|
}, 25000);
|
||||||
|
return () => {
|
||||||
|
clearTimeout(timeout);
|
||||||
|
callToLong.current!.pause();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}, [isTransmitting]);
|
||||||
|
};
|
||||||
@@ -34,7 +34,7 @@ export const SituationBoard = () => {
|
|||||||
<div className="w-px bg-gray-400 mx-2" />
|
<div className="w-px bg-gray-400 mx-2" />
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
<h2 className="inline-flex items-center gap-2 text-lg font-bold mb-2">
|
<h2 className="inline-flex items-center gap-2 text-lg font-bold mb-2">
|
||||||
<Plane /> Stations
|
<Plane /> Stationen
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
8
apps/dispatch/app/_helpers/useDebounce.ts
Normal file
8
apps/dispatch/app/_helpers/useDebounce.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import { DependencyList, useEffect } from "react";
|
||||||
|
import useTimeout from "./useTimeout";
|
||||||
|
|
||||||
|
export const useDebounce = (callback: () => void, delay: number, dependencies: DependencyList) => {
|
||||||
|
const { reset, clear } = useTimeout(callback, delay);
|
||||||
|
useEffect(reset, [...dependencies, reset]);
|
||||||
|
useEffect(() => clear, [clear]);
|
||||||
|
};
|
||||||
30
apps/dispatch/app/_helpers/useTimeout.ts
Normal file
30
apps/dispatch/app/_helpers/useTimeout.ts
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import { useCallback, useEffect, useRef } from "react";
|
||||||
|
|
||||||
|
export default function useTimeout(callback: () => void, delay: number) {
|
||||||
|
const callbackRef = useRef(callback);
|
||||||
|
const timeoutRef = useRef<NodeJS.Timeout>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
callbackRef.current = callback;
|
||||||
|
}, [callback]);
|
||||||
|
|
||||||
|
const set = useCallback(() => {
|
||||||
|
timeoutRef.current = setTimeout(() => callbackRef.current(), delay);
|
||||||
|
}, [delay]);
|
||||||
|
|
||||||
|
const clear = useCallback(() => {
|
||||||
|
if (timeoutRef.current) clearTimeout(timeoutRef.current);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
set();
|
||||||
|
return clear;
|
||||||
|
}, [delay, set, clear]);
|
||||||
|
|
||||||
|
const reset = useCallback(() => {
|
||||||
|
clear();
|
||||||
|
set();
|
||||||
|
}, [clear, set]);
|
||||||
|
|
||||||
|
return { reset, clear, set };
|
||||||
|
}
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import { Connection } from "./_components/Connection";
|
import { Connection } from "./_components/Connection";
|
||||||
/* import { ThemeSwap } from "./_components/ThemeSwap"; */
|
/* import { ThemeSwap } from "./_components/ThemeSwap"; */
|
||||||
import { Audio } from "../../../_components/Audio";
|
import { Audio } from "../../../_components/Audio/Audio";
|
||||||
/* import { useState } from "react"; */
|
/* import { useState } from "react"; */
|
||||||
import { ExitIcon, ExternalLinkIcon } from "@radix-ui/react-icons";
|
import { ExitIcon, ExternalLinkIcon } from "@radix-ui/react-icons";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import { Connection } from "./_components/Connection";
|
import { Connection } from "./_components/Connection";
|
||||||
/* import { ThemeSwap } from "./ThemeSwap"; */
|
/* import { ThemeSwap } from "./ThemeSwap"; */
|
||||||
import { Audio } from "../../../_components/Audio";
|
import { Audio } from "../../../_components/Audio/Audio";
|
||||||
/* import { useState } from "react"; */
|
/* import { useState } from "react"; */
|
||||||
import { ExitIcon, ExternalLinkIcon } from "@radix-ui/react-icons";
|
import { ExitIcon, ExternalLinkIcon } from "@radix-ui/react-icons";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
|||||||
BIN
apps/dispatch/public/sounds/call_blocked_sepura.wav
Normal file
BIN
apps/dispatch/public/sounds/call_blocked_sepura.wav
Normal file
Binary file not shown.
BIN
apps/dispatch/public/sounds/call_end_sepura.wav
Normal file
BIN
apps/dispatch/public/sounds/call_end_sepura.wav
Normal file
Binary file not shown.
BIN
apps/dispatch/public/sounds/call_interrupted_by_admin.mp3
Normal file
BIN
apps/dispatch/public/sounds/call_interrupted_by_admin.mp3
Normal file
Binary file not shown.
BIN
apps/dispatch/public/sounds/call_to_long.wav
Normal file
BIN
apps/dispatch/public/sounds/call_to_long.wav
Normal file
Binary file not shown.
BIN
apps/dispatch/public/sounds/connection_started_sepura.mp3
Normal file
BIN
apps/dispatch/public/sounds/connection_started_sepura.mp3
Normal file
Binary file not shown.
BIN
apps/dispatch/public/sounds/connection_stoped_sepura.mp3
Normal file
BIN
apps/dispatch/public/sounds/connection_stoped_sepura.mp3
Normal file
Binary file not shown.
Reference in New Issue
Block a user