From 2e7dfe85e6e2fe0815c3acd4dd1885eb4cdf79fa Mon Sep 17 00:00:00 2001 From: Robert Long Date: Thu, 7 Oct 2021 17:25:40 -0700 Subject: [PATCH 1/2] WIP --- src/Room.jsx | 30 +++++++++++++++-- src/RoomButton.jsx | 71 ++++++++++++++++++++++++++++++++++----- src/RoomButton.module.css | 36 ++++++++++++++++++-- 3 files changed, 125 insertions(+), 12 deletions(-) diff --git a/src/Room.jsx b/src/Room.jsx index 68012a5e..b6a124d7 100644 --- a/src/Room.jsx +++ b/src/Room.jsx @@ -78,7 +78,7 @@ export function Room({ client }) { return (
- +
); } @@ -224,6 +224,8 @@ function RoomSetupView({ ); } +function useMediaManager() {} + function InRoomView({ roomName, microphoneMuted, @@ -239,6 +241,15 @@ function InRoomView({ }) { const [layout, toggleLayout] = useVideoGridLayout(); + const { + audioDeviceId, + audioDevices, + setAudioDevice, + videoDeviceId, + videoDevices, + setVideoDevice, + } = useMediaManager(); + const items = useMemo(() => { const participants = []; @@ -284,10 +295,25 @@ function InRoomView({ )}
- + setAudioDevice(value)} + options={audioDevices.map(({ label, deviceId }) => ({ + label, + value: deviceId, + }))} + /> setVideoDevice(value)} + options={videoDevices.map(({ label, deviceId }) => ({ + label, + value: deviceId, + }))} /> { + function onClick() { + if (open) { + setOpen(false); + } + } + + window.addEventListener("click", onClick); + + return () => { + window.removeEventListener("click", onClick); + }; + }, [open]); + return ( - - {muted ? : } - +
+ {children} + + {open && ( +
+
    + {options.map((item) => ( +
  • onChange(item)} + > + {item.label} +
  • + ))} +
+
+ )} +
); } -export function VideoButton({ enabled, ...rest }) { +export function MicButton({ muted, onChange, value, options, ...rest }) { return ( - - {enabled ? : } - + + + {muted ? : } + + + ); +} + +export function VideoButton({ enabled, onChange, value, ...rest }) { + return ( + + + {enabled ? : } + + ); } diff --git a/src/RoomButton.module.css b/src/RoomButton.module.css index c0f62d1d..97fced4c 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,34 @@ 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; +} + +.dropdownButton:hover { + background-color: #8d97a5; +} + +.dropdownButton:hover svg * { + fill: #8d97a5; +} + +.dropdownContainer { + position: absolute; + left: 50%; + transform: translate(-50%, -100%); + top: 0; + background-color: #394049; + border-radius: 8px; +} From 5a714cef8d11ce7aac9aa593f449ef889be78a84 Mon Sep 17 00:00:00 2001 From: Robert Long Date: Tue, 12 Oct 2021 16:52:20 -0700 Subject: [PATCH 2/2] Add mic/webcam switching --- src/Room.jsx | 114 ++++++++++++++++++++++++++++++-------- src/RoomButton.jsx | 31 +++++------ src/RoomButton.module.css | 26 ++++++++- 3 files changed, 127 insertions(+), 44 deletions(-) diff --git a/src/Room.jsx b/src/Room.jsx index b6a124d7..60ccd20d 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"; @@ -83,7 +84,7 @@ export function Room({ client }) { ); } -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, @@ -242,13 +305,13 @@ function InRoomView({ const [layout, toggleLayout] = useVideoGridLayout(); const { - audioDeviceId, - audioDevices, - setAudioDevice, - videoDeviceId, - videoDevices, - setVideoDevice, - } = useMediaManager(); + audioInput, + audioInputs, + setAudioInput, + videoInput, + videoInputs, + setVideoInput, + } = useMediaHandler(client); const items = useMemo(() => { const participants = []; @@ -295,26 +358,29 @@ function InRoomView({ )}
- setAudioDevice(value)} - options={audioDevices.map(({ label, deviceId }) => ({ + setAudioInput(value)} + options={audioInputs.map(({ label, deviceId }) => ({ label, value: deviceId, }))} - /> - setVideoDevice(value)} - options={videoDevices.map(({ label, deviceId }) => ({ + > + + + setVideoInput(value)} + options={videoInputs.map(({ label, deviceId }) => ({ label, value: deviceId, }))} - /> + > + + +
{children} {open && ( -
+
    {options.map((item) => (
  • onChange(item)} > @@ -73,23 +72,19 @@ export function DropdownButton({ onChange, options, children }) { ); } -export function MicButton({ muted, onChange, value, options, ...rest }) { +export function MicButton({ muted, ...rest }) { return ( - - - {muted ? : } - - + + {muted ? : } + ); } -export function VideoButton({ enabled, onChange, value, ...rest }) { +export function VideoButton({ enabled, ...rest }) { return ( - - - {enabled ? : } - - + + {enabled ? : } + ); } diff --git a/src/RoomButton.module.css b/src/RoomButton.module.css index 97fced4c..ed38c28f 100644 --- a/src/RoomButton.module.css +++ b/src/RoomButton.module.css @@ -87,6 +87,7 @@ limitations under the License. position: absolute; bottom: 0; right: 0; + cursor: pointer; } .dropdownButton:hover { @@ -100,8 +101,29 @@ limitations under the License. .dropdownContainer { position: absolute; left: 50%; - transform: translate(-50%, -100%); - top: 0; + 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; }