Add VoiceButtonContainer logic

This commit is contained in:
Robert Long 2020-10-21 13:56:29 -07:00
Родитель adfc22bc34
Коммит 8ecd1a2ac2
10 изменённых файлов: 86 добавлений и 16 удалений

Просмотреть файл

@ -35,7 +35,10 @@ module.exports = {
template: require("../src/react-components/icons/IconTemplate"),
svgoConfig: {
plugins: {
removeViewBox: false
removeViewBox: false,
mergePaths: false,
convertShapeToPath: false,
removeHiddenElems: false
}
}
}

Просмотреть файл

@ -55,7 +55,6 @@ AFRAME.registerComponent("mute-mic", {
if (!NAF.connection.adapter) return;
if (!this.el.sceneEl.is("entered")) return;
this.el.sceneEl.systems["hubs-systems"].soundEffectsSystem.playSoundOneShot(SOUND_TOGGLE_MIC);
if (this.el.is("muted")) {
NAF.connection.adapter.enableMicrophone(true);
this.el.removeState("muted");

Просмотреть файл

@ -1,5 +1,6 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7.5 17.5006H12.5" stroke="black" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<rect x="8" y="8.69995" width="4" height="0" fill="#7ED320"/>
<path d="M15 8.12573V9.37573C15 12.1257 12.75 14.3757 10 14.3757C7.25 14.3757 5 12.1257 5 9.37573V8.12573" stroke="black" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M9.99976 14.3761V17.5011" stroke="black" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M10 2.50028C9.67126 2.49862 9.34543 2.56215 9.04137 2.6872C8.7373 2.81225 8.46105 2.99634 8.22857 3.22882C7.99609 3.46129 7.81201 3.73755 7.68696 4.04161C7.56191 4.34567 7.49838 4.67151 7.50003 5.00028V9.33621C7.50003 10.7112 8.63284 11.8753 10 11.8753C11.3672 11.8753 12.5 10.7425 12.5 9.33621V5.00028C12.5 3.59403 11.4063 2.50028 10 2.50028Z" stroke="black" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>

До

Ширина:  |  Высота:  |  Размер: 959 B

После

Ширина:  |  Высота:  |  Размер: 1021 B

Просмотреть файл

@ -1,5 +1,6 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7.5 17.5006H12.5" stroke="black" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<rect x="8" y="8.69995" width="4" height="0" fill="#7ED320"/>
<path d="M15 8.12573V9.37573C15 12.1257 12.75 14.3757 10 14.3757C7.25 14.3757 5 12.1257 5 9.37573V8.12573" stroke="black" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M9.99976 14.3761V17.5011" stroke="black" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M10 2.50028C9.67126 2.49862 9.34543 2.56215 9.04137 2.6872C8.7373 2.81225 8.46105 2.99634 8.22857 3.22882C7.99609 3.46129 7.81201 3.73755 7.68696 4.04161C7.56191 4.34567 7.49838 4.67151 7.50003 5.00028V9.33621C7.50003 10.7112 8.63284 11.8753 10 11.8753C11.3672 11.8753 12.5 10.7425 12.5 9.33621V5.00028C12.5 3.59403 11.4063 2.50028 10 2.50028Z" stroke="black" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>

До

Ширина:  |  Высота:  |  Размер: 1.1 KiB

После

Ширина:  |  Высота:  |  Размер: 1.1 KiB

Просмотреть файл

@ -1,7 +1,7 @@
import React from "react";
import PropTypes from "prop-types";
import { MicSetupModal } from "./MicSetupModal";
import { useMicrophoneVolume } from "./useMicrophoneVolume";
import { useMicrophone } from "./useMicrophone";
import { useSound } from "./useSound";
import webmSrc from "../../assets/sfx/tone.webm";
import mp3Src from "../../assets/sfx/tone.mp3";
@ -9,7 +9,7 @@ import oggSrc from "../../assets/sfx/tone.ogg";
import wavSrc from "../../assets/sfx/tone.wav";
export function MicSetupModalContainer({ scene, ...rest }) {
const volume = useMicrophoneVolume(scene);
const { volume } = useMicrophone(scene);
const [soundPlaying, playSound] = useSound({ webmSrc, mp3Src, oggSrc, wavSrc });
return <MicSetupModal micLevel={volume} soundPlaying={soundPlaying} onPlaySound={playSound} {...rest} />;
}

6
src/react-components/room/PeopleSidebar.js поставляемый
Просмотреть файл

@ -54,10 +54,10 @@ function getVoiceLabel(micPresence) {
function getVoiceIconComponent(micPresence) {
if (micPresence) {
if (micPresence.talking) {
return VolumeHighIcon;
} else if (micPresence.muted) {
if (micPresence.muted) {
return VolumeMutedIcon;
} else if (micPresence.talking) {
return VolumeHighIcon;
}
}

45
src/react-components/room/VoiceButtonContainer.js поставляемый Normal file
Просмотреть файл

@ -0,0 +1,45 @@
import React, { useEffect, useRef } from "react";
import PropTypes from "prop-types";
import { ReactComponent as MicrophoneIcon } from "../icons/Microphone.svg";
import { ReactComponent as MicrophoneMutedIcon } from "../icons/MicrophoneMuted.svg";
import { ToolbarButton } from "../input/ToolbarButton";
import { useMicrophone } from "./useMicrophone";
export function VoiceButtonContainer({ scene, microphoneEnabled }) {
const buttonRef = useRef();
const { isMuted, volume, toggleMute } = useMicrophone(scene);
useEffect(
() => {
const rect = buttonRef.current.querySelector("rect");
if (volume < 0.05) {
rect.setAttribute("height", 0);
} else if (volume < 0.3) {
rect.setAttribute("y", 8);
rect.setAttribute("height", 4);
} else {
rect.setAttribute("y", 4);
rect.setAttribute("height", 8);
}
},
[volume, isMuted]
);
return (
<ToolbarButton
ref={buttonRef}
icon={isMuted || !microphoneEnabled ? <MicrophoneMutedIcon /> : <MicrophoneIcon />}
label="Voice"
preset="basic"
onClick={toggleMute}
statusColor={microphoneEnabled ? "green" : undefined}
/>
);
}
VoiceButtonContainer.propTypes = {
scene: PropTypes.object.isRequired,
microphoneEnabled: PropTypes.bool
};

Просмотреть файл

@ -1,17 +1,17 @@
import { useState, useEffect, useRef } from "react";
import { useState, useEffect, useRef, useCallback } from "react";
import MovingAverage from "moving-average";
const MOVING_AVG_TIMESPAN = 100;
const UPDATE_RATE = 50;
export function useMicrophoneVolume(scene) {
export function useMicrophone(scene, updateRate = UPDATE_RATE) {
const movingAvgRef = useRef();
const [isMuted, setIsMuted] = useState(scene.is("muted"));
const [volume, setVolume] = useState(0);
useEffect(
() => {
if (!movingAvgRef.current) {
movingAvgRef.current = MovingAverage(MOVING_AVG_TIMESPAN);
movingAvgRef.current = MovingAverage(updateRate * 2);
}
let max = 0;
@ -31,12 +31,30 @@ export function useMicrophoneVolume(scene) {
updateMicVolume();
function onSceneStateChange(event) {
if (event.detail === "muted") {
setIsMuted(scene.is("muted"));
}
}
scene.addEventListener("stateadded", onSceneStateChange);
scene.addEventListener("stateremoved", onSceneStateChange);
return () => {
clearTimeout(timeout);
scene.removeEventListener("stateadded", onSceneStateChange);
scene.removeEventListener("stateremoved", onSceneStateChange);
};
},
[setVolume, scene]
[setVolume, scene, updateRate]
);
return volume;
const toggleMute = useCallback(
() => {
scene.emit("action_mute");
},
[scene]
);
return { isMuted, volume, toggleMute };
}

4
src/react-components/ui-root.js поставляемый
Просмотреть файл

@ -91,7 +91,6 @@ import { ReactComponent as DiscordIcon } from "./icons/Discord.svg";
import { ReactComponent as VRIcon } from "./icons/VR.svg";
import { ReactComponent as PeopleIcon } from "./icons/People.svg";
import { ReactComponent as ObjectsIcon } from "./icons/Objects.svg";
import { ReactComponent as MicrophoneIcon } from "./icons/Microphone.svg";
import { ReactComponent as ReactionIcon } from "./icons/Reaction.svg";
import { ReactComponent as LeaveIcon } from "./icons/Leave.svg";
import { PeopleSidebarContainer, userFromPresence } from "./room/PeopleSidebarContainer";
@ -101,6 +100,7 @@ import { ObjectMenuContainer } from "./room/ObjectMenuContainer";
import { useCssBreakpoints } from "react-use-css-breakpoints";
import { PlacePopoverContainer } from "./room/PlacePopoverContainer";
import { SharePopoverContainer } from "./room/SharePopoverContainer";
import { VoiceButtonContainer } from "./room/VoiceButtonContainer";
const avatarEditorDebug = qsTruthy("avatarEditorDebug");
@ -1894,7 +1894,7 @@ class UIRoot extends Component {
<>
{entered && (
<>
<ToolbarButton icon={<MicrophoneIcon />} label="Voice" preset="basic" />
<VoiceButtonContainer scene={this.props.scene} microphoneEnabled={!!this.state.audioTrack} />
<SharePopoverContainer scene={this.props.scene} hubChannel={this.props.hubChannel} />
<PlacePopoverContainer
scene={this.props.scene}

Просмотреть файл

@ -396,7 +396,10 @@ module.exports = async (env, argv) => {
template: require("./src/react-components/icons/IconTemplate"),
svgoConfig: {
plugins: {
removeViewBox: false
removeViewBox: false,
mergePaths: false,
convertShapeToPath: false,
removeHiddenElems: false
}
}
}