feat(frontend): assist func
This commit is contained in:
parent
0c78d83774
commit
70159bbeb6
6 changed files with 71 additions and 89 deletions
|
|
@ -1,49 +1,12 @@
|
|||
import React, { useEffect, useRef } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { findDOMNode } from 'react-dom';
|
||||
import {
|
||||
PlayerProvider,
|
||||
attach as attachPlayer,
|
||||
init as initPlayer,
|
||||
clean as cleanPlayer,
|
||||
callPeer,
|
||||
// scale
|
||||
} from 'App/player';
|
||||
import ChatWindow from './ChatWindow/ChatWindow'
|
||||
//import ScreenSharing from './ScreenSharing/ScreenSharing'
|
||||
import React from 'react';
|
||||
import ChatWindow from './ChatWindow/ChatWindow';
|
||||
|
||||
function Assist({ session, jwt }) {
|
||||
const screeRef = useRef<HTMLDivElement>(null);
|
||||
useEffect(() => {
|
||||
initPlayer(session, jwt);
|
||||
return () => cleanPlayer()
|
||||
}, [ session.sessionId ]);
|
||||
|
||||
useEffect(() => {
|
||||
if (screeRef.current) {
|
||||
attachPlayer(findDOMNode(screeRef.current));
|
||||
}
|
||||
}, [ ])
|
||||
export default function Assist() {
|
||||
|
||||
return (
|
||||
<div className="absolute">
|
||||
{/* <div ref={screeRef}
|
||||
// Just for testing TODO: flexible layout.
|
||||
// It should consider itself as empty but take maximum of the space available
|
||||
// Screen will adapt automatically.
|
||||
style={{height: "300px", width:"600px" }}
|
||||
className="relative overflow-hidden bg-gray-lightest"
|
||||
/> */}
|
||||
<ChatWindow call={ callPeer } />
|
||||
<ChatWindow />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default connect(state => ({
|
||||
// session: { // Testing mock. Should be retrieved from redux
|
||||
// // startedAt: 1624314191394,
|
||||
// live: true,
|
||||
// // sessionId: "4870254843916045",
|
||||
// },
|
||||
jwt: state.get('jwt'),
|
||||
}))(Assist);
|
||||
|
|
|
|||
|
|
@ -1,41 +1,31 @@
|
|||
import React, { useState, useEffect } from 'react';
|
||||
import { IconButton } from 'UI';
|
||||
//import { IconButton } from 'UI';
|
||||
import VideoContainer from '../components/VideoContainer';
|
||||
import stl from './chatWindow.css';
|
||||
import { callPeer } from 'App/player';
|
||||
|
||||
interface Props {
|
||||
call: (oStream: MediaStream, cb: (iStream: MediaStream)=>void)=>void
|
||||
}
|
||||
// export interface Props {
|
||||
// call: (oStream: MediaStream, cb: (iStream: MediaStream)=>void)=>void
|
||||
// }
|
||||
|
||||
function ChatWindow({ call }: Props) {
|
||||
function ChatWindow() {
|
||||
const [ inputStream, setInputStream ] = useState<MediaStream | null>(null);
|
||||
const [ outputStream, setOutputStream ] = useState<MediaStream | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
startOutputStream()
|
||||
callPeer()
|
||||
}, [])
|
||||
|
||||
const startOutputStream = () => {
|
||||
navigator.mediaDevices.getUserMedia({video:true, audio:true})
|
||||
.then(oStream => {
|
||||
setOutputStream(oStream);
|
||||
call(oStream, setInputStream); // Returns false when unable to connect.
|
||||
callPeer(oStream, setInputStream, () => {
|
||||
console.log('endd')
|
||||
outputStream?.getTracks().forEach(t => t.stop());
|
||||
//inputStream?.
|
||||
}); // Returns false when unable to connect.
|
||||
// TODO: handle calling state
|
||||
})
|
||||
.catch(console.log) // TODO: handle error in ui
|
||||
}
|
||||
}, [])
|
||||
|
||||
// const onCallClick = () => {
|
||||
// navigator.mediaDevices.getUserMedia({video:true, audio:true})
|
||||
// .then(oStream => {
|
||||
// setOutputStream(oStream);
|
||||
// call(oStream, setInputStream); // Returns false when unable to connect.
|
||||
// // TODO: handle calling state
|
||||
// })
|
||||
// .catch(console.log) // TODO: handle error in ui
|
||||
// }
|
||||
return (
|
||||
<div className="fixed border radius bg-white z-50 shadow-xl mt-16">
|
||||
<div className="p-2">
|
||||
|
|
|
|||
|
|
@ -2,13 +2,13 @@ import React, { useState, useEffect, useRef } from 'react'
|
|||
import { Button, Icon } from 'UI'
|
||||
|
||||
interface Props {
|
||||
stream: MediaProvider | null
|
||||
stream: MediaStream | null
|
||||
muted?: boolean
|
||||
}
|
||||
|
||||
function VideoContainer({ stream, muted = false }: Props) {
|
||||
const [muteAudio, setMuteAudio] = useState(false)
|
||||
const [muteVideo, setMuteVideo] = useState(false)
|
||||
const [audioEnabled, setAudioEnabled] = useState(true)
|
||||
const [videoEnabled, setVideoEnabled] = useState(true)
|
||||
const ref = useRef<HTMLVideoElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
|
|
@ -18,13 +18,17 @@ function VideoContainer({ stream, muted = false }: Props) {
|
|||
}, [ ref.current, stream ])
|
||||
|
||||
const toggleAudio = () => {
|
||||
// stream.getAudioTracks().forEach(track => track.enabled = !track.enabled);
|
||||
setMuteAudio(!muteAudio)
|
||||
if (!stream) { return; }
|
||||
const aEn = !audioEnabled
|
||||
stream.getAudioTracks().forEach(track => track.enabled = aEn);
|
||||
setAudioEnabled(aEn);
|
||||
}
|
||||
|
||||
const toggleVideo = () => {
|
||||
// stream.getVideoTracks().forEach(track => track.enabled = !track.enabled);
|
||||
setMuteVideo(!muteVideo)
|
||||
if (!stream) { return; }
|
||||
const vEn = !videoEnabled;
|
||||
stream.getVideoTracks().forEach(track => track.enabled = vEn);
|
||||
setVideoEnabled(vEn)
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
@ -33,11 +37,11 @@ function VideoContainer({ stream, muted = false }: Props) {
|
|||
<video autoPlay ref={ ref } muted={ muted } />
|
||||
<div className="flex items-center absolute w-full justify-center bottom-0 bg-gray-lightest">
|
||||
<Button plain size="small" onClick={toggleAudio}>
|
||||
<Icon name={muteAudio ? 'mic-mute' : 'mic'} size="16" />
|
||||
<Icon name={audioEnabled ? 'mic' : 'mic-mute'} size="16" />
|
||||
</Button>
|
||||
|
||||
<Button plain size="small" onClick={toggleVideo}>
|
||||
<Icon name={ muteVideo ? 'camera-video-off' : 'camera-video' } size="16" />
|
||||
<Icon name={ videoEnabled ? 'camera-video' : 'camera-video-off' } size="16" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ const ScreenWrapper = withOverlay()(React.memo(() => <div className={ stl.screen
|
|||
loading: state.messagesLoading,
|
||||
disconnected: state.disconnected,
|
||||
disabled: state.cssLoading || state.messagesLoading || state.inspectorMode,
|
||||
inspectorMode: state.inspectorMode,
|
||||
removeOverlay: state.inspectorMode || state.live,
|
||||
completed: state.completed,
|
||||
autoplay: state.autoplay
|
||||
}))
|
||||
|
|
@ -96,7 +96,7 @@ export default class Player extends React.PureComponent {
|
|||
className,
|
||||
playing,
|
||||
disabled,
|
||||
inspectorMode,
|
||||
removeOverlay,
|
||||
bottomBlockIsActive,
|
||||
loading,
|
||||
disconnected,
|
||||
|
|
@ -125,7 +125,7 @@ export default class Player extends React.PureComponent {
|
|||
// />
|
||||
}
|
||||
<div className="relative flex-1">
|
||||
{ !inspectorMode &&
|
||||
{ !removeOverlay &&
|
||||
<div
|
||||
className={ stl.overlay }
|
||||
onClick={ disabled ? null : this.togglePlay }
|
||||
|
|
|
|||
|
|
@ -139,17 +139,30 @@ export default class MessageDistributor extends StatedScreen {
|
|||
}
|
||||
}
|
||||
|
||||
private getPeerID(): string {
|
||||
return `${this.session.projectKey}-${this.session.sessionId}`
|
||||
}
|
||||
|
||||
private peer: Peer | null = null;
|
||||
private connectToPeer() {
|
||||
this.setMessagesLoading(true);
|
||||
import('peerjs').then(({ default: Peer }) => {
|
||||
const peer = new Peer();
|
||||
// @ts-ignore
|
||||
console.log(new URL(window.ENV.API_EDP).host)
|
||||
const peer = new Peer({
|
||||
// @ts-ignore
|
||||
host: new URL(window.ENV.API_EDP).host,
|
||||
path: '/assist',
|
||||
port: 80,
|
||||
});
|
||||
this.peer = peer;
|
||||
peer.on("open", me => {
|
||||
console.log("peer opened", me);
|
||||
const id = `3sWXSsqHgSKnEO5YkNJK-${this.session.sessionId}`;
|
||||
const id = this.getPeerID();
|
||||
console.log("trying to connect to", id)
|
||||
const conn = peer.connect(id);
|
||||
console.log("Peer ", peer)
|
||||
|
||||
conn.on('open', () => {
|
||||
this.setMessagesLoading(false);
|
||||
let i = 0;
|
||||
|
|
@ -177,22 +190,33 @@ export default class MessageDistributor extends StatedScreen {
|
|||
});
|
||||
}
|
||||
|
||||
callPeer(localStream: MediaStream, cb: (s: MediaStream)=>void): boolean {
|
||||
if (!this.peer) { return false; }
|
||||
const conn = this.peer.connections[`3sWXSsqHgSKnEO5YkNJK-${this.session.sessionId}`]?.[0];
|
||||
if (!conn || !conn.open) { return false; } // Conn not established
|
||||
callPeer(localStream: MediaStream, onStream: (s: MediaStream)=>void, onClose: () => void, onRefuse?: ()=> void): ()=>void {
|
||||
if (!this.peer) { return Function; }
|
||||
const conn = this.peer.connections[this.getPeerID()]?.[0];
|
||||
if (!conn || !conn.open) { return Function; } // Conn not established
|
||||
const call = this.peer.call(conn.peer, localStream);
|
||||
console.log('calling...')
|
||||
// on refuse?
|
||||
call.on('stream', function(stream) {
|
||||
cb(stream);
|
||||
});
|
||||
call.on('stream', onStream);
|
||||
call.on("close", onClose);
|
||||
call.on("error", onClose)
|
||||
|
||||
return () => call.close();
|
||||
}
|
||||
|
||||
requestMouse(): ()=>void {
|
||||
if (!this.peer) { return Function; }
|
||||
const conn = this.peer.connections[this.getPeerID()]?.[0];
|
||||
if (!conn || !conn.open) { return Function; }
|
||||
const onMouseMove = (e) => {
|
||||
// @ts-ignore
|
||||
const data = this._getInternalCoordinates(e)
|
||||
conn.send({ x: Math.round(data.x), y: Math.round(data.y) }); // debounce?
|
||||
}
|
||||
//@ts-ignore
|
||||
this.document?.
|
||||
addEventListener("mousemove", ({ x, y }) => {
|
||||
conn.send([ x, y ]); // debounce?
|
||||
});
|
||||
return true;
|
||||
this.overlay.addEventListener("mousemove", onMouseMove);
|
||||
//@ts-ignore
|
||||
return () => this.overlay.removeEventListener("mousemove", onMouseMove);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -419,7 +443,6 @@ export default class MessageDistributor extends StatedScreen {
|
|||
}
|
||||
break;
|
||||
case "set_viewport_size":
|
||||
console.log("setvvs", msg)
|
||||
this.resizeManager.add(msg);
|
||||
break;
|
||||
case "mouse_move":
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@ function hashString(s: string): number {
|
|||
export default Record({
|
||||
sessionId: '',
|
||||
siteId: '',
|
||||
projectKey: '',
|
||||
peerId: '',
|
||||
live: true,
|
||||
startedAt: 0,
|
||||
duration: 0,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue