diff --git a/web/src/components/player/HlsVideoPlayer.tsx b/web/src/components/player/HlsVideoPlayer.tsx index cbf5e2b5d..6d6df7268 100644 --- a/web/src/components/player/HlsVideoPlayer.tsx +++ b/web/src/components/player/HlsVideoPlayer.tsx @@ -17,8 +17,16 @@ import { DropdownMenuRadioItem, DropdownMenuTrigger, } from "../ui/dropdown-menu"; -import { MdForward10, MdReplay10 } from "react-icons/md"; +import { + MdForward10, + MdReplay10, + MdVolumeDown, + MdVolumeMute, + MdVolumeOff, + MdVolumeUp, +} from "react-icons/md"; import useKeyboardListener from "@/hooks/use-keyboard-listener"; +import { Slider } from "../ui/slider-volume"; const HLS_MIME_TYPE = "application/vnd.apple.mpegurl" as const; const unsupportedErrorCodes = [ @@ -166,6 +174,7 @@ export default function HlsVideoPlayer({ autoPlay controls={false} playsInline + muted onPlay={() => { setIsPlaying(true); @@ -280,6 +289,22 @@ function VideoControls({ [isPlaying, video], ); + // volume control + + const VolumeIcon = useMemo(() => { + if (!video || video?.muted) { + return MdVolumeOff; + } else if (video.volume <= 0.33) { + return MdVolumeMute; + } else if (video.volume <= 0.67) { + return MdVolumeDown; + } else { + return MdVolumeUp; + } + // only update when specific fields change + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [video?.volume, video?.muted]); + if (!video || !show) { return; } @@ -288,6 +313,25 @@ function VideoControls({
+
+ { + e.stopPropagation(); + video.muted = !video.muted; + }} + /> + {video.muted == false && ( + (video.volume = value[0])} + /> + )} +
{isPlaying ? ( diff --git a/web/src/components/ui/slider-volume.tsx b/web/src/components/ui/slider-volume.tsx new file mode 100644 index 000000000..1493488a3 --- /dev/null +++ b/web/src/components/ui/slider-volume.tsx @@ -0,0 +1,26 @@ +import * as React from "react"; +import * as SliderPrimitive from "@radix-ui/react-slider"; + +import { cn } from "@/lib/utils"; + +const Slider = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + + + + + + +)); +Slider.displayName = SliderPrimitive.Root.displayName; + +export { Slider };