| import * as THREE from 'three'; | |
| import {Button} from '@mui/material'; | |
| import {useCallback, useEffect, useState} from 'react'; | |
| import {BufferedSpeechPlayer} from '../createBufferedSpeechPlayer'; | |
| type Props = { | |
| bufferedSpeechPlayer: BufferedSpeechPlayer; | |
| renderer: THREE.WebGLRenderer | null; | |
| onARVisible?: () => void; | |
| onARHidden?: () => void; | |
| }; | |
| export default function ARButton({ | |
| bufferedSpeechPlayer, | |
| renderer, | |
| onARVisible, | |
| onARHidden, | |
| }: Props) { | |
| const [session, setSession] = useState<XRSession | null>(null); | |
| const [supported, setSupported] = useState<boolean>(true); | |
| useEffect(() => { | |
| if (!navigator.xr) { | |
| setSupported(false); | |
| return; | |
| } | |
| navigator.xr.isSessionSupported('immersive-ar').then((supported) => { | |
| setSupported(supported); | |
| }); | |
| }, []); | |
| const resetBuffers = useCallback( | |
| (event: XRSessionEvent) => { | |
| const session = event.target; | |
| if (!(session instanceof XRSession)) { | |
| return; | |
| } | |
| switch (session.visibilityState) { | |
| case 'visible': | |
| console.log('Restarting speech player, device is visible'); | |
| bufferedSpeechPlayer.stop(); | |
| bufferedSpeechPlayer.start(); | |
| onARVisible?.(); | |
| break; | |
| case 'hidden': | |
| console.log('Stopping speech player, device is hidden'); | |
| bufferedSpeechPlayer.stop(); | |
| bufferedSpeechPlayer.start(); | |
| onARHidden?.(); | |
| break; | |
| } | |
| }, | |
| [bufferedSpeechPlayer], | |
| ); | |
| async function onSessionStarted(session: XRSession) { | |
| setSession(session); | |
| session.onvisibilitychange = resetBuffers; | |
| session.onend = onSessionEnded; | |
| await renderer.xr.setSession(session); | |
| } | |
| function onSessionEnded() { | |
| setSession(null); | |
| } | |
| const onClick = () => { | |
| if (session === null) { | |
| navigator.xr!.requestSession('immersive-ar').then(onSessionStarted); | |
| } else { | |
| session.end(); | |
| } | |
| }; | |
| return ( | |
| <Button | |
| variant="contained" | |
| onClick={onClick} | |
| disabled={!supported || renderer == null} | |
| sx={{mt: 1}}> | |
| {supported | |
| ? renderer != null | |
| ? 'Enter AR' | |
| : 'Initializing AR...' | |
| : 'AR Not Supported'} | |
| </Button> | |
| ); | |
| } | |