split compnent & spa.

This commit is contained in:
Miroslav Šedivý 2020-11-06 20:49:05 +01:00
parent 7c9be1fd45
commit 67573f26ef
4 changed files with 257 additions and 156 deletions

View File

@ -1,155 +0,0 @@
<template>
<div ref="component" class="video">
<button @click="connect()">Connect</button>
<button @click="disconnect()">Disonnect</button><br />
websocket_state: {{ websocket_state }}<br />
webrtc_state: {{ webrtc_state }}<br />
<div ref="container" class="player-container">
<video ref="video" />
<neko-overlay
v-if="websocket_state == 'connected' && webrtc_state == 'connected'"
:webrtc="webrtc"
:screenWidth="1280"
:screenHeight="720"
:scrollSensitivity="5"
:scrollInvert="true"
:isControling="true"
/>
</div>
</div>
</template>
<style lang="scss" scoped>
.player-container {
position: relative;
width: 1280px;
height: 720px;
video {
position: absolute;
top: 0;
bottom: 0;
width: 100%;
height: 100%;
display: flex;
background: #000;
&::-webkit-media-controls {
display: none !important;
}
}
}
</style>
<script lang="ts">
import ResizeObserver from 'resize-observer-polyfill'
import { Vue, Component, Ref, Watch } from 'vue-property-decorator'
import { NekoWebSocket } from './internal/websocket'
import { NekoWebRTC } from './internal/webrtc'
import Overlay from '~/components/overlay.vue'
@Component({
name: 'neko',
components: {
'neko-overlay': Overlay,
},
})
export default class extends Vue {
@Ref('component') readonly _component!: HTMLElement
@Ref('container') readonly _container!: HTMLElement
@Ref('video') readonly _video!: HTMLVideoElement
private observer = new ResizeObserver(this.onResize.bind(this))
websocket: NekoWebSocket | null = null
webrtc: NekoWebRTC | null = null
private websocket_state = 'disconnected'
private webrtc_state = 'disconnected'
public connect() {
try {
this.websocket?.connect('ws://192.168.1.20:3000/', 'admin')
} catch (e) {}
}
public disconnect() {
this.websocket?.disconnect()
}
mounted() {
// Update canvas on resize
this._container.addEventListener('resize', this.onResize)
this.observer.observe(this._component)
// WebSocket
this.websocket = new NekoWebSocket()
this.websocket?.on('message', async (event: string, payload: any) => {
switch (event) {
case 'signal/provide':
try {
let sdp = await this.webrtc?.connect(payload.sdp, payload.lite, payload.ice)
this.websocket?.send('signal/answer', { sdp, displayname: 'test' })
} catch (e) {}
break
case 'screen/resolution':
payload.width
payload.height
payload.rate
break
default:
console.log(event, payload)
}
})
this.websocket?.on('connecting', () => {
this.websocket_state = 'connecting'
})
this.websocket?.on('connected', () => {
this.websocket_state = 'connected'
})
this.websocket?.on('disconnected', () => {
this.websocket_state = 'disconnected'
this.webrtc?.disconnect()
})
// WebRTC
this.webrtc = new NekoWebRTC()
this.webrtc?.on('track', (event: RTCTrackEvent) => {
const { track, streams } = event
if (track.kind === 'audio') {
return
}
// Create stream
if ('srcObject' in this._video) {
this._video.srcObject = streams[0]
} else {
// @ts-ignore
this._video.src = window.URL.createObjectURL(streams[0]) // for older browsers
}
this._video.play()
})
this.webrtc?.on('connecting', () => {
this.webrtc_state = 'connecting'
})
this.webrtc?.on('connected', () => {
this.webrtc_state = 'connected'
})
this.webrtc?.on('disconnected', () => {
this.webrtc_state = 'disconnected'
})
}
destroyed() {
this.webrtc?.disconnect()
this.websocket?.disconnect()
}
public onResize() {
console.log('Resize event triggered.')
}
}
</script>

54
src/app.vue Normal file
View File

@ -0,0 +1,54 @@
<template>
<div>
<button @click="connect()">Connect</button>
<button @click="disconnect()">Disonnect</button>
<button @click="neko.control.request()">request control</button>
<button @click="neko.control.release()">release control</button>
<button @click="neko.video.pause()">stop</button><br />
W: <input type="text" v-model="width" /><br />
H: <input type="text" v-model="height" /><br />
<button @click="resize()">Resize</button>
<br />
<!--websocket_state: {{ websocket_state }}<br />
webrtc_state: {{ webrtc_state }}<br />-->
<div ref="container" style="width:1280px;height:720px;border: 2px solid red;">
<neko-canvas ref="neko" />
</div>
</div>
</template>
<style lang="scss" scoped></style>
<script lang="ts">
import { Vue, Component, Ref, Watch } from 'vue-property-decorator'
import Neko from '~/components/canvas.vue'
@Component({
name: 'neko',
components: {
'neko-canvas': Neko,
},
})
export default class extends Vue {
@Ref('container') readonly container!: HTMLElement
@Ref('neko') readonly neko!: Neko
width = '720px'
height = '1280px'
connect() {
this.neko.connect('ws://192.168.1.20:3000/', 'neko')
}
disconnect() {
this.neko.disconnect()
}
resize() {
this.container.style.width = this.width
this.container.style.height = this.height
}
}
</script>

202
src/components/canvas.vue Normal file
View File

@ -0,0 +1,202 @@
<template>
<div ref="component" class="component">
<div ref="container" class="player-container">
<video ref="video" />
<neko-overlay
v-if="websocket_state == 'connected' && webrtc_state == 'connected'"
:webrtc="webrtc"
:screenWidth="state.screen_size.width"
:screenHeight="state.screen_size.height"
:scrollSensitivity="5"
:scrollInvert="true"
:isControling="true"
/>
</div>
</div>
</template>
<style lang="scss" scoped>
.component {
width: 100%;
height: 100%;
}
.player-container {
position: relative;
video {
position: absolute;
top: 0;
bottom: 0;
width: 100%;
height: 100%;
display: flex;
background: #000;
&::-webkit-media-controls {
display: none !important;
}
}
}
</style>
<script lang="ts">
import { Vue, Component, Ref, Watch, Prop } from 'vue-property-decorator'
import ResizeObserver from 'resize-observer-polyfill'
import { NekoWebSocket } from '~/internal/websocket'
import { NekoWebRTC } from '~/internal/webrtc'
import Overlay from './overlay.vue'
@Component({
name: 'neko-canvas',
components: {
'neko-overlay': Overlay,
},
})
export default class extends Vue {
@Ref('component') readonly _component!: HTMLElement
@Ref('container') readonly _container!: HTMLElement
@Ref('video') public readonly video!: HTMLVideoElement
private websocket = new NekoWebSocket()
private webrtc = new NekoWebRTC()
private observer = new ResizeObserver(this.onResize.bind(this))
private state = {
screen_size: {
width: Number,
height: Number,
rate: Number,
},
}
private websocket_state = 'disconnected'
private webrtc_state = 'disconnected'
public control = {
request: () => {
this.websocket.send('control/request')
},
release: () => {
this.websocket.send('control/release')
},
}
public connect(url: string, password: string) {
if (this.websocket.connected) {
throw new Error('client already connected')
}
this.websocket.connect(url, password)
}
public disconnect() {
if (!this.websocket.connected) {
throw new Error('client not connected')
}
this.websocket.disconnect()
}
private mounted() {
// Update canvas on resize
this.observer.observe(this._component)
// WebSocket
this.websocket.on('message', async (event: string, payload: any) => {
switch (event) {
case 'signal/provide':
try {
let sdp = await this.webrtc.connect(payload.sdp, payload.lite, payload.ice)
this.websocket.send('signal/answer', { sdp, displayname: 'test' })
} catch (e) {}
break
case 'screen/resolution':
Vue.set(this.state, 'screen_size', payload)
this.onResize()
break
default:
console.log(event, payload)
}
})
this.websocket.on('connecting', () => {
this.websocket_state = 'connecting'
})
this.websocket.on('connected', () => {
this.websocket_state = 'connected'
})
this.websocket.on('disconnected', () => {
this.websocket_state = 'disconnected'
this.webrtc.disconnect()
})
// WebRTC
this.webrtc.on('track', (event: RTCTrackEvent) => {
const { track, streams } = event
if (track.kind === 'audio') {
return
}
// Create stream
if ('srcObject' in this.video) {
this.video.srcObject = streams[0]
} else {
// @ts-ignore
this.video.src = window.URL.createObjectURL(streams[0]) // for older browsers
}
this.video.play()
})
this.webrtc.on('connecting', () => {
this.webrtc_state = 'connecting'
})
this.webrtc.on('connected', () => {
this.webrtc_state = 'connected'
})
this.webrtc.on('disconnected', () => {
this.webrtc_state = 'disconnected'
})
}
private beforeDestroy() {
this.webrtc.disconnect()
this.websocket.disconnect()
}
private onResize() {
console.log('Resize event triggered.')
const { width, height } = this.state.screen_size
const screen_ratio = width / height
const { offsetWidth, offsetHeight } = this._component
const canvas_ratio = offsetWidth / offsetHeight
// Vertical centering
if(screen_ratio > canvas_ratio) {
const vertical = offsetWidth / screen_ratio
this._container.style.width = `${offsetWidth}px`
this._container.style.height = `${vertical}px`
this._container.style.marginTop = `${(offsetHeight - vertical) / 2}px`
this._container.style.marginLeft = `0px`
}
// Horizontal centering
else if(screen_ratio < canvas_ratio) {
const horizontal = screen_ratio * offsetHeight
this._container.style.width = `${horizontal}px`
this._container.style.height = `${offsetHeight}px`
this._container.style.marginTop = `0px`
this._container.style.marginLeft = `${(offsetWidth - horizontal) / 2}px`
}
// No centering
else {
this._container.style.width = `${offsetWidth}px`
this._container.style.height = `${offsetHeight}px`
this._container.style.marginTop = `0px`
this._container.style.marginLeft = `0px`
}
}
}
</script>

View File

@ -1,5 +1,5 @@
// Import vue component // Import vue component
import Neko from './Neko.vue'; import Neko from './components/canvas.vue';
// Declare install function executed by Vue.use() // Declare install function executed by Vue.use()
export function install(Vue) { export function install(Vue) {