diff --git a/webapp/components/device.tsx b/webapp/components/device.tsx index e0d1dd2..9cfb54d 100644 --- a/webapp/components/device.tsx +++ b/webapp/components/device.tsx @@ -1,19 +1,13 @@ +import useWhipClient from "./use/whip" import { useEffect, useState } from 'react' import { useAtom } from 'jotai' import { Device, deviceNone, deviceScreen, - asyncGetAudioStream, - asyncGetVideoStream, } from '../lib/device' import { - localStreamAtom, - enabledAudioAtom, - enabledVideoAtom, - localUserStatusAtom, - currentDeviceAudioAtom, - currentDeviceVideoAtom, + localStreamIdAtom, } from '../store/atom' import Loading from './svg/loading' @@ -25,17 +19,22 @@ export default function DeviceBar() { const [permissionAudio, setPermissionAudio] = useState("...") const [permissionVideo, setPermissionVideo] = useState("...") - const [localStream, setLocalStream] = useAtom(localStreamAtom) - const [localUserStatus, setLocalUserStatus] = useAtom(localUserStatusAtom) + const [localStreamId] = useAtom(localStreamIdAtom) const [loadingAudio, setLoadingAudio] = useState(false) const [loadingVideo, setLoadingVideo] = useState(false) const [loadingScreen, setLoadingScreen] = useState(false) - const [enabledAudio] = useAtom(enabledAudioAtom) - const [enabledVideo] = useAtom(enabledVideoAtom) - const [currentDeviceAudio, setCurrentDeviceAudio] = useAtom(currentDeviceAudioAtom) - const [currentDeviceVideo, setCurrentDeviceVideo] = useAtom(currentDeviceVideoAtom) + const { + userStatus, + currentDeviceAudio, + currentDeviceVideo, + setCurrentDeviceAudio, + setCurrentDeviceVideo, + toggleEnableAudio, + toggleEnableVideo, + } = useWhipClient(localStreamId) + const [deviceAudio, setDeviceAudio] = useState([deviceNone]) const [deviceVideo, setDeviceVideo] = useState([deviceNone]) @@ -70,16 +69,12 @@ export default function DeviceBar() { if (currentDeviceAudio === deviceNone.deviceId) { let device = audios[0] - if (device) { - setCurrentDeviceAudio(device.deviceId) - } + if (device) await setCurrentDeviceAudio(device.deviceId) } if (currentDeviceVideo === deviceNone.deviceId) { let device = videos[0] - if (device) { - setCurrentDeviceVideo(device.deviceId) - } + if (device) await setCurrentDeviceVideo(device.deviceId) } setDeviceAudio([...audios]) @@ -88,6 +83,7 @@ export default function DeviceBar() { const init = async () => { try { + (await navigator.mediaDevices.getUserMedia({ video: true, audio: true })).getTracks().map(track => track.stop()) // NOTE: // In some device have problem: // - Android Web Browser @@ -99,7 +95,7 @@ export default function DeviceBar() { useEffect(() => { init() - }, [localStream]) + }, []) useEffect(() => { // Reference: https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/devicechange_event @@ -107,81 +103,21 @@ export default function DeviceBar() { return () => { navigator.mediaDevices.removeEventListener("devicechange", updateDeviceList) } }, []) - const toggleEnableAudio = async () => { - if (enabledAudio) { - onChangedDeviceAudio(deviceNone.deviceId) - } else { - onChangedDeviceAudio(currentDeviceAudio) - } - } - const onChangedDeviceAudio = async (current: string) => { setLoadingAudio(true) - // Closed old tracks - const stream = localStream.stream - stream.getAudioTracks().map(track => { - track.stop() - stream.removeTrack(track) - }) - - const mediaStream = await asyncGetAudioStream(current) - - const videoTracks = localStream.stream.getVideoTracks() - const audioTracks = mediaStream.getAudioTracks() - - setLocalStream({ - stream: new MediaStream([...audioTracks, ...videoTracks]), - name: "Me", - }) - - setLocalUserStatus({ - ...localUserStatus, - audio: current === deviceNone.deviceId ? false : true, - }) - - current === deviceNone.deviceId ? null : setCurrentDeviceAudio(current) + await setCurrentDeviceAudio(current) setLoadingAudio(false) } - const toggleEnableVideo = async () => { - if (enabledVideo) { - onChangedDeviceVideo(deviceNone.deviceId) - } else { - onChangedDeviceVideo(currentDeviceVideo) - } - } - const onChangedDeviceVideo = async (current: string) => { setLoadingVideo(true) - // Closed old tracks - const stream = localStream.stream - stream.getVideoTracks().map(track => { - track.stop() - stream.removeTrack(track) - }) - - const mediaStream = await asyncGetVideoStream(current) - const audioTracks = localStream.stream.getAudioTracks() - const videoTracks = mediaStream.getVideoTracks() - - setLocalStream({ - stream: new MediaStream([...audioTracks, ...videoTracks]), - name: "Me", - }) - - setLocalUserStatus({ - ...localUserStatus, - video: current === deviceNone.deviceId ? false : true, - screen: current === deviceScreen.deviceId ? true : false, - }) - - current === deviceNone.deviceId ? null : setCurrentDeviceVideo(current) + await setCurrentDeviceVideo(current) setLoadingVideo(false) } const toggleEnableScreen = async () => { setLoadingScreen(true) - if (localUserStatus.screen) { + if (userStatus.screen) { await onChangedDeviceVideo(deviceNone.deviceId) } else { await onChangedDeviceVideo(deviceScreen.deviceId) @@ -206,7 +142,7 @@ export default function DeviceBar() { ?
:
} - {enabledAudio + {userStatus.audio ?
:
:
} - {enabledVideo + {userStatus.video ?
:
{loadingScreen ? - : localUserStatus.screen ? : + : userStatus.screen ? : } diff --git a/webapp/components/layout.tsx b/webapp/components/layout.tsx index df6fb5f..737f6ac 100644 --- a/webapp/components/layout.tsx +++ b/webapp/components/layout.tsx @@ -70,7 +70,7 @@ export default function Layout(props: { meetingId: string }) {
{ enabledPresentation - ? + ? : null } diff --git a/webapp/components/player/player.tsx b/webapp/components/player/player.tsx index fb78ca2..6065d9d 100644 --- a/webapp/components/player/player.tsx +++ b/webapp/components/player/player.tsx @@ -1,14 +1,13 @@ import { useEffect, useRef, useState } from 'react' -import { UserStream } from '../../store/atom' import WaveSurfer from 'wavesurfer.js' import RecordPlugin from 'wavesurfer.js/dist/plugins/record' import { isWechat } from '../../lib/util' -function AudioWave(props: { user: UserStream }) { +function AudioWave(props: { stream: MediaStream }) { const refWave = useRef(null) useEffect(() => { - if (refWave.current && !!props.user.stream?.getAudioTracks().length) { + if (refWave.current && !!props.stream?.getAudioTracks().length) { const wavesurfer = WaveSurfer.create({ container: refWave.current, waveColor: 'rgb(200, 100, 0)', @@ -16,7 +15,7 @@ function AudioWave(props: { user: UserStream }) { }) const record = wavesurfer.registerPlugin(RecordPlugin.create()) - const { onDestroy, onEnd } = record.renderMicStream(props.user.stream) + const { onDestroy, onEnd } = record.renderMicStream(props.stream) return () => { onDestroy() @@ -24,27 +23,27 @@ function AudioWave(props: { user: UserStream }) { wavesurfer.destroy() } } - }, [refWave.current, props.user.stream]) + }, [refWave.current, props.stream]) return
} -export default function Player(props: { user: UserStream, muted: boolean, width: string, display: string }) { +export default function Player(props: { stream: MediaStream, muted: boolean, width: string, display: string }) { const refVideo = useRef(null) const [showAudio, setShowAudio] = useState(false) useEffect(() => { - if (props.user.stream?.getAudioTracks().length !== 0 && props.user.stream?.getVideoTracks().length === 0) { + if (props.stream?.getAudioTracks().length !== 0 && props.stream?.getVideoTracks().length === 0) { setShowAudio(true) } else { setShowAudio(false) } - }, [props.user.stream]) + }, [props.stream]) useEffect(() => { if (refVideo.current) { - refVideo.current.srcObject = props.user.stream + refVideo.current.srcObject = props.stream // NOTE: About Autoplay // Reference: https://developer.mozilla.org/en-US/docs/Web/Media/Autoplay_guide @@ -54,7 +53,7 @@ export default function Player(props: { user: UserStream, muted: boolean, width: // https://developers.weixin.qq.com/community/develop/doc/0006a61de48ab0165f99e1dcd51c00 if (isWechat()) refVideo.current.play() } - }, [refVideo, props.user.stream]); + }, [refVideo, props.stream]) // NOTE: iOS can't display video // https://webkit.org/blog/6784/new-video-policies-for-ios/ @@ -67,10 +66,10 @@ export default function Player(props: { user: UserStream, muted: boolean, width: controls={false} muted={props.muted} ref={refVideo} - style={!!props.user.stream?.getVideoTracks().length ? { width: props.width } : { height: '0px' }} + style={!!props.stream?.getVideoTracks().length ? { width: props.width } : { height: '0px' }} /> {props.display === "full" || showAudio - ? + ? : null } diff --git a/webapp/components/player/whep-player.tsx b/webapp/components/player/whep-player.tsx index c0c9fb3..6edb353 100644 --- a/webapp/components/player/whep-player.tsx +++ b/webapp/components/player/whep-player.tsx @@ -98,7 +98,7 @@ export default function WhepPlayer(props: { streamId: string, status: UserStatus
{ loading ?
- : + : }
diff --git a/webapp/components/player/whip-player.tsx b/webapp/components/player/whip-player.tsx index dfe89a1..c720032 100644 --- a/webapp/components/player/whip-player.tsx +++ b/webapp/components/player/whip-player.tsx @@ -1,39 +1,12 @@ -import { useEffect } from "react" import useWhipClient from "../use/whip" import Player from './player' -import { useAtom } from 'jotai' -import { - localStreamAtom, - localUserStatusAtom, - - currentDeviceAudioAtom, - currentDeviceVideoAtom, -} from '../../store/atom' export default function WhipPlayer(props: { streamId: string, width: string }) { - // TODO: Need fix - // - name - // - audio - // - video - const [localUserStatus] = useAtom(localUserStatusAtom) - const [localStream] = useAtom(localStreamAtom) - const { userStatus, setCurrentDeviceAudio, setCurrentDeviceVideo, restart } = useWhipClient(localUserStatus.name, props.streamId, localStream.stream) - - const [currentDeviceAudio] = useAtom(currentDeviceAudioAtom) - const [currentDeviceVideo] = useAtom(currentDeviceVideoAtom) - - useEffect(() => { - setCurrentDeviceAudio(currentDeviceAudio) - }, [currentDeviceAudio]) - - useEffect(() => { - setCurrentDeviceVideo(currentDeviceVideo) - }, [currentDeviceVideo]) - + const { stream, userStatus, restart } = useWhipClient(props.streamId) return (
- +
(false) - const refEnabled = useRef(false) const [displayName, setDisplayName] = useState("") - const [localStream, setLocalStream] = useAtom(localStreamAtom) const [localStreamId] = useAtom(localStreamIdAtom) - const [localUserStatus, setLocalUserStatus] = useAtom(localUserStatusAtom) const [_, setMeetingJoined] = useAtom(meetingJoinedAtom) - const start = async () => { + const { stream, setUserName, start} = useWhipClient(localStreamId) + + const join = async () => { setLoading(true) - setLocalUserStatus({ - ...localUserStatus, - name: displayName || localStreamId, - }) + setUserName(displayName || localStreamId) setLoading(false) setMeetingJoined(true) setStorageName(displayName) - } - - const init = async () => { - try { - setDisplayName(getStorageName() || "") - - const stream = await navigator.mediaDevices.getUserMedia({ video: { width: 320 }, audio: true }) - setLocalStream({ - stream: stream, - name: "Me", - }) - - setLocalUserStatus({ - ...localUserStatus, - audio: true, - video: true, - }) - - } catch { } + start() } useEffect(() => { - if (!refEnabled.current) { - refEnabled.current = true - init() - } + setDisplayName(getStorageName() || "") }, []) return (
- +
@@ -81,7 +55,7 @@ export default function Prepare(props: { meetingId: string }) {
-