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;
+}