UNPKG

maxme-electron

Version:

The electron wrap of MaxME.

284 lines (258 loc) 8.54 kB
import GLRender from 'webgl-video-renderer'; import React, { Component } from "react"; import PropTypes from 'prop-types'; import 'bootstrap/dist/css/bootstrap.min.css'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faSpinner, faVideoSlash, faMicrophoneAltSlash, faLongArrowAltDown, faLongArrowAltUp} from '@fortawesome/free-solid-svg-icons'; import MicrophoneIndicator from './MicrophoneIndicator.jsx'; import uuid4 from 'uuid/v4'; class VideoRender extends Component { constructor(props) { super(props); this.previewId = 0; this.activeVideoId = 0; this.epUUID = ""; this.desktopId = 0; this.microphoneIndicator = undefined; this.canvasId = uuid4(); this.sink = undefined; this.state = { isPreview:false, displayName:this.props.displayName, stateBar:this.props.stateBar, loading:false, // should show loading shade muted:false, // should show video muted shade audioMuted:false, // the endpoint's microphone was muted audioLevel:0, // the audio level of endpoint uplink:'green', // the score of network uplink downlink:'green' // the score of netwrok downlink }; } componentDidMount() { const canvas = document.getElementById(this.canvasId); this.glContext = GLRender.setupCanvas(canvas); } componentWillUnmount() { resetSink.call(this); } preview() { if (this.sink == undefined) { this.setState({loading:true}); const id = Math.random() * 100000000000000000; const rlt = maxme.video.addPreview(id); if (rlt.errno == 0) { this.previewId = id; this.setState({isPreview:true}); setSink.call(this, rlt.sink); } } } stopPreview() { if (this.previewId != 0) { resetSink.call(this); maxme.video.rmPreview(this.previewId); this.previewId = 0; this.setState({isPreview:false}); this.glContext.fillBlack(); } } subscribeActive(quality) { if (this.sink == undefined) { this.setState({loading:true}); const id = Math.random() * 100000000000000000; const rlt = maxme.video.subActive(id, quality); if (rlt.errno == 0) { this.activeVideoId = id; setSink.call(this, rlt.sink); } } } unsubscribeActive() { if (this.activeVideoId) { resetSink.call(this); maxme.video.unsubActive(this.activeVideoId); this.activeVideoId = 0; this.glContext.fillBlack(); } } subscribe(uuid, quality) { if(this.sink == undefined) { this.setState({loading:true}); const rlt = maxme.video.subscribe(uuid, quality); if (rlt.errno == 0) { this.epUUID = uuid; setSink.call(this, rlt.sink); } } } unsbscribe() { if(this.epUUID != "") { resetSink.call(this); maxme.video.unsubscribe(this.epUUID); this.epUUID = ""; this.glContext.fillBlack(); } } subscribeDesktop() { if (this.sink == undefined) { const id = Math.random() * 100000000000000000; const rlt = maxme.desktop.subActive(); if (rlt.errno == 0) { this.desktopId = id; setSink.call(this, rlt.sink); } } } unsubscribeDesktop() { if (this.desktopId) { resetSink.call(this); maxme.desktop.unsubActive(); this.desktopId = 0; this.glContext.fillBlack(); } } render() { const style = { stateBar :{ bottom:'1px', width:this.props.width, height:'30px', background:(this.props.stateBar) ? 'rgba(100, 100, 100, 0.3)' : 'rgba(100, 100, 100, 0)', zIndex:this.props.zIndex + 20 }, shade : { width: this.props.width + 2, height: this.props.height + 2, background:'rgba(0, 0, 0, 1.0)', zIndex:this.props.zIndex + 10, bottom:'0px', paddingTop:'20%', textAlign:'center' }, canvas : { width:this.props.width, height:this.props.height, backgroundColor:'black', zIndex:this.props.zIndex } }; return ( <div className={this.state.actived ? 'position-relative border border-primary' : 'position-relative '} style={{width:this.props.width+2,height:this.props.height+2}}> {this.state.loading && <div className="position-absolute text-secondary" style={style.shade}> <FontAwesomeIcon icon={faSpinner} size="2x" spin /> </div> } {(this.state.muted || (this.state.isPreview && maxme.video.muted)) && <div className="position-absolute text-secondary" style={style.shade} > <FontAwesomeIcon icon={faVideoSlash} size="2x" /> </div> } {this.state.stateBar && <div className="position-absolute " style={style.stateBar}> <div className="float-left" style={{paddingLeft:'10px', paddingTop:'3px'}}> <label className="text-white d-inline">{this.state.displayName}</label> </div> <div className="float-left" style={{marginLeft:'5px', paddingTop:'3px'}}> <span className='d-inline'><FontAwesomeIcon icon={faLongArrowAltUp} color={this.state.uplink} /></span> <span className='d-inline'><FontAwesomeIcon icon={faLongArrowAltDown} color={this.state.downlink} /></span> </div> <div className="float-left" style={{marginLeft:'5px', paddingTop:'3px'}}> {(this.state.audioMuted || (this.state.isPreview === true && maxme.audio.localMuted === true)) ? (<FontAwesomeIcon icon={faMicrophoneAltSlash} color={'white'} />) : (<MicrophoneIndicator ref= { (indicator) => { if(indicator) { this.microphoneIndicator = indicator; } } }/>) } </div> </div> } <canvas id={this.canvasId} style={style.canvas} /> </div> ); } } function setSink(sink) { this.sink = sink; this.setState({displayName:sink.nick}); this.sink.onFirstFrame = () => { this.setState({loading : false}); } this.sink.onFrameReady = (frame) => { if(this.glContext) { this.glContext.render(frame, frame.width, frame.height, frame.uOffset, frame.vOffset); } } this.sink.onMuted = () => { this.setState({muted:true}); } this.sink.onDemuted = () => { this.setState({muted:false}); } this.sink.onQualityChanged = (ev) => { let color = 'green'; switch (ev.quality) { case 'worst': color = 'red'; break; case 'bad': color = 'orange'; break; case 'poor': color = 'yellow'; break; case 'excellent': case 'good': default: color = 'green'; break; } ev.position == 'up' ? this.setState({uplink:color}) : this.setState({downlink:color}); } this.sink.onSourceChanged = () => { this.setState({displayName:sink.nick}); } this.sink.onActived = (value)=> { this.setState({actived:value}); } this.sink.onAudioMuted = () => { this.setState({audioMuted:true}); } this.sink.onAudioDemuted = () => { this.setState({audioMuted: false}); } this.sink.onVolume = (vol) => { if (this.microphoneIndicator) { this.microphoneIndicator.setState({volume:vol}); } } } function resetSink() { if (this.sink) { this.sink.onFirstFrame = undefined; this.sink.onFrameReady = undefined; this.sink.onActived = undefined; this.sink.onAudioDemuted = undefined; this.sink.onAudioMuted = undefined; this.sink.onMuted = undefined; this.sink.onDemuted = undefined; this.sink.onVolume = undefined; this.sink.onSourceChanged = undefined; this.sink.onQualityChanged = undefined; this.sink = undefined; } } VideoRender.propTypes = { width: PropTypes.number.isRequired, height: PropTypes.number.isRequired, zIndex: PropTypes.number.isRequired, stateBar: PropTypes.bool.isRequired, displayName: PropTypes.string }; export default VideoRender;