2021-08-20 02:11:02 +10:00
|
|
|
import styles from "./Panes.module.scss";
|
|
|
|
import { Text } from "preact-i18n";
|
|
|
|
|
|
|
|
import { connectState } from "../../../redux/connector";
|
|
|
|
|
|
|
|
import { voiceState, VoiceStatus } from "../../../lib/vortex/VoiceState";
|
|
|
|
|
2021-09-08 14:12:15 +02:00
|
|
|
import { TextReact } from "../../../lib/i18n";
|
|
|
|
|
2021-08-20 02:11:02 +10:00
|
|
|
import ComboBox from "../../../components/ui/ComboBox";
|
2021-09-08 14:12:15 +02:00
|
|
|
import Overline from "../../../components/ui/Overline";
|
|
|
|
import Tip from "../../../components/ui/Tip";
|
2021-08-20 02:11:02 +10:00
|
|
|
import {useEffect, useState} from "preact/hooks";
|
2021-09-08 14:12:15 +02:00
|
|
|
import { stopPropagation } from "../../../lib/stopPropagation";
|
|
|
|
|
|
|
|
|
|
|
|
const constraints = { audio: true }
|
2021-08-20 02:11:02 +10:00
|
|
|
|
|
|
|
export function Component() {
|
2021-09-08 14:12:15 +02:00
|
|
|
const [mediaStream, setMediaStream] = useState<MediaStream|undefined>(undefined)
|
2021-08-20 02:11:02 +10:00
|
|
|
const [mediaDevices, setMediaDevices] = useState<MediaDeviceInfo[] | undefined>(undefined);
|
2021-09-08 14:12:15 +02:00
|
|
|
const [permission, setPermission] = useState<PermissionState | undefined>(undefined);
|
|
|
|
const [error, setError] = useState<DOMException | undefined>(undefined)
|
|
|
|
|
|
|
|
const askOrGetPermission = async () => {
|
|
|
|
try {
|
|
|
|
const mediaStream = await navigator.mediaDevices.getUserMedia(constraints)
|
|
|
|
setMediaStream(mediaStream)
|
|
|
|
} catch (err) {
|
|
|
|
// The user has blocked the permission
|
|
|
|
setError(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
const { state } = await navigator.permissions.query({ name: 'microphone' })
|
|
|
|
setPermission(state)
|
|
|
|
|
|
|
|
} catch (err) {
|
|
|
|
// the browser might not support `query` functionnality
|
|
|
|
setError(err);
|
|
|
|
}
|
|
|
|
}
|
2021-08-20 02:11:02 +10:00
|
|
|
|
|
|
|
useEffect(() => {
|
2021-09-08 14:12:15 +02:00
|
|
|
askOrGetPermission()
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
if (!mediaStream) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-08-20 02:11:02 +10:00
|
|
|
navigator
|
|
|
|
.mediaDevices
|
|
|
|
.enumerateDevices()
|
|
|
|
.then( devices => {
|
|
|
|
setMediaDevices(devices)
|
2021-09-08 14:12:15 +02:00
|
|
|
}, err => {
|
|
|
|
setError(err)
|
2021-08-20 02:11:02 +10:00
|
|
|
})
|
2021-09-08 14:12:15 +02:00
|
|
|
|
|
|
|
}, [mediaStream])
|
|
|
|
|
|
|
|
const handleAskForPermission = (ev: JSX.TargetedMouseEvent<HTMLAnchorElement>) => {
|
|
|
|
stopPropagation(ev)
|
|
|
|
setError(undefined)
|
|
|
|
askOrGetPermission()
|
|
|
|
}
|
2021-08-20 02:11:02 +10:00
|
|
|
|
|
|
|
return (
|
|
|
|
<>
|
|
|
|
<div>
|
|
|
|
<h3>
|
|
|
|
<Text id="app.settings.pages.audio.input_device" />
|
|
|
|
</h3>
|
|
|
|
<ComboBox
|
|
|
|
value={window.localStorage.getItem("audioInputDevice") ?? 0}
|
|
|
|
onChange={(e) => changeAudioDevice(e.currentTarget.value, "input")}>
|
|
|
|
{
|
|
|
|
mediaDevices?.filter(device => device.kind === "audioinput").map(device => {
|
|
|
|
return (
|
|
|
|
<option value={device.deviceId} key={device.deviceId}>
|
2021-09-08 14:12:15 +02:00
|
|
|
{device.label || <Text id="app.settings.pages.audio.device_label_NA"/>}
|
2021-08-20 02:11:02 +10:00
|
|
|
</option>
|
|
|
|
)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
</ComboBox>
|
2021-09-08 14:12:15 +02:00
|
|
|
{error && error.name === 'NotAllowedError' &&
|
|
|
|
<Overline error="AudioPermissionBlock" type="error" block />}
|
|
|
|
|
|
|
|
{error && permission === 'prompt' &&
|
|
|
|
<Tip>
|
|
|
|
<TextReact id="app.settings.pages.audio.tip_retry" fields={{
|
|
|
|
retryBtn: (
|
|
|
|
<a onClick={handleAskForPermission}>
|
|
|
|
<Text id="app.settings.pages.audio.button_retry" />
|
|
|
|
</a>
|
|
|
|
),
|
|
|
|
}}/>
|
|
|
|
</Tip>
|
|
|
|
}
|
2021-08-20 02:11:02 +10:00
|
|
|
</div>
|
|
|
|
</>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
function changeAudioDevice(deviceId: string, deviceType: string) {
|
|
|
|
if(deviceType === "input") {
|
|
|
|
window.localStorage.setItem("audioInputDevice", deviceId)
|
|
|
|
if(voiceState.isProducing("audio")) {
|
|
|
|
voiceState.stopProducing("audio");
|
|
|
|
voiceState.startProducing("audio");
|
|
|
|
}
|
|
|
|
}else if(deviceType === "output") {
|
|
|
|
window.localStorage.setItem("audioOutputDevice", deviceId)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export const Audio = connectState(Component, () => {
|
|
|
|
return;
|
|
|
|
});
|