diff --git a/src/Room.jsx b/src/Room.jsx index 68012a5..60ccd20 100644 --- a/src/Room.jsx +++ b/src/Room.jsx @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React, { useEffect, useMemo, useState } from "react"; +import React, { useCallback, useEffect, useMemo, useState } from "react"; import styles from "./Room.module.css"; import { useLocation, useParams } from "react-router-dom"; import { @@ -23,6 +23,7 @@ import { VideoButton, LayoutToggleButton, ScreenshareButton, + DropdownButton, } from "./RoomButton"; import { Header, LeftNav, RightNav, CenterNav } from "./Header"; import { Button } from "./Input"; @@ -78,12 +79,12 @@ export function Room({ client }) { return (
- +
); } -export function GroupCallView({ groupCall }) { +export function GroupCallView({ client, groupCall }) { const { state, error, @@ -108,6 +109,7 @@ export function GroupCallView({ groupCall }) { } else if (state === GroupCallState.Entered) { return ( { + function updateDevices() { + navigator.mediaDevices.enumerateDevices().then((devices) => { + const audioInputs = devices.filter( + (device) => device.kind === "audioinput" + ); + const videoInputs = devices.filter( + (device) => device.kind === "videoinput" + ); + + setState((prevState) => ({ + ...prevState, + audioInputs, + videoInputs, + })); + }); + } + + updateDevices(); + + navigator.mediaDevices.addEventListener("devicechange", updateDevices); + + return () => { + navigator.mediaDevices.removeEventListener("devicechange", updateDevices); + }; + }, []); + + const setAudioInput = useCallback( + (deviceId) => { + setState((prevState) => ({ ...prevState, audioInput: deviceId })); + client.getMediaHandler().setAudioInput(deviceId); + }, + [client] + ); + + const setVideoInput = useCallback( + (deviceId) => { + setState((prevState) => ({ ...prevState, videoInput: deviceId })); + client.getMediaHandler().setVideoInput(deviceId); + }, + [client] + ); + + return { + audioInput, + audioInputs, + setAudioInput, + videoInput, + videoInputs, + setVideoInput, + }; +} + function InRoomView({ + client, roomName, microphoneMuted, localVideoMuted, @@ -239,6 +304,15 @@ function InRoomView({ }) { const [layout, toggleLayout] = useVideoGridLayout(); + const { + audioInput, + audioInputs, + setAudioInput, + videoInput, + videoInputs, + setVideoInput, + } = useMediaHandler(client); + const items = useMemo(() => { const participants = []; @@ -284,11 +358,29 @@ function InRoomView({ )}
- - + setAudioInput(value)} + options={audioInputs.map(({ label, deviceId }) => ({ + label, + value: deviceId, + }))} + > + + + setVideoInput(value)} + options={videoInputs.map(({ label, deviceId }) => ({ + label, + value: deviceId, + }))} + > + + { + function onClick() { + if (open) { + setOpen(false); + } + } + + window.addEventListener("click", onClick); + + return () => { + window.removeEventListener("click", onClick); + }; + }, [open]); + + return ( +
+ {children} + + {open && ( +
+
    + {options.map((item) => ( +
  • onChange(item)} + > + {item.label} +
  • + ))} +
+
+ )} +
+ ); +} + export function MicButton({ muted, ...rest }) { return ( diff --git a/src/RoomButton.module.css b/src/RoomButton.module.css index c0f62d1..ed38c28 100644 --- a/src/RoomButton.module.css +++ b/src/RoomButton.module.css @@ -15,7 +15,8 @@ limitations under the License. */ .roomButton, -.headerButton { +.headerButton, +.dropdownButton { display: flex; justify-content: center; align-items: center; @@ -29,7 +30,7 @@ limitations under the License. width: 50px; height: 50px; border-radius: 50px; - background-color: rgba(111, 120, 130, 0.3); + background-color: #394049; } .roomButton:hover { @@ -73,3 +74,56 @@ limitations under the License. .screenshareButton.on svg * { fill: #0dbd8b; } + +.dropdownButtonContainer { + position: relative; +} + +.dropdownButton { + width: 15px; + height: 15px; + border-radius: 15px; + background-color: #394049; + position: absolute; + bottom: 0; + right: 0; + cursor: pointer; +} + +.dropdownButton:hover { + background-color: #8d97a5; +} + +.dropdownButton:hover svg * { + fill: #8d97a5; +} + +.dropdownContainer { + position: absolute; + left: 50%; + transform: translate(0, -100%); + top: -5px; + background-color: #394049; + border-radius: 8px; + overflow: hidden; +} + +.dropdownContainer ul { + list-style: none; + margin: 0; + padding: 0; +} + +.dropdownContainer li { + padding: 12px; + width: 200px; + cursor: pointer; +} + +.dropdownContainer li:hover { + background-color: #8d97a5; +} + +.dropdownActiveItem { + color: #0dbd8b; +}