Compare commits

...

4 Commits

Author SHA1 Message Date
Mustafa Yontar eb68c1e5c9 kick add 5 years ago
Mustafa Yontar 4bff32dabb some changes 5 years ago
Mustafa Yontar 71e39389b8 add vuex 5 years ago
Mustafa Yontar 9baa128cad add login screen 5 years ago
  1. 53
      package-lock.json
  2. 4
      package.json
  3. 37
      src/App.vue
  4. 5
      src/lib/RemoteFeed.vue
  5. 54
      src/lib/VueJanus.vue
  6. 5
      src/main.js
  7. 2
      src/plugins/axios.js
  8. 34
      src/router/index.js
  9. 17
      src/store/index.js
  10. 19
      src/views/Home.vue
  11. 83
      src/views/Room.vue
  12. 59
      src/views/RoomView.vue
  13. 51
      src/views/login.vue

53
package-lock.json generated

@ -1273,18 +1273,47 @@
}
},
"@vue/cli-plugin-router": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/@vue/cli-plugin-router/-/cli-plugin-router-4.2.3.tgz",
"integrity": "sha512-RGtgFQCTMS1X1wtFt752RMgr/LlF9cfpH37MkwjhF2wpnyTp+hkKl/09QORAKW91I8iFpZFH7xZKMBS3r1WbCw==",
"version": "4.3.1",
"resolved": "https://registry.npm.taobao.org/@vue/cli-plugin-router/download/@vue/cli-plugin-router-4.3.1.tgz",
"integrity": "sha1-C6WJ9Omh8+ZKj/bM2S984oRVhr8=",
"dev": true,
"requires": {
"@vue/cli-shared-utils": "^4.2.3"
"@vue/cli-shared-utils": "^4.3.1"
},
"dependencies": {
"@vue/cli-shared-utils": {
"version": "4.3.1",
"resolved": "https://registry.npm.taobao.org/@vue/cli-shared-utils/download/@vue/cli-shared-utils-4.3.1.tgz",
"integrity": "sha1-p0v01Tgl1KSwWoSwPgI5dIcbw4o=",
"dev": true,
"requires": {
"@hapi/joi": "^15.0.1",
"chalk": "^2.4.2",
"execa": "^1.0.0",
"launch-editor": "^2.2.1",
"lru-cache": "^5.1.1",
"node-ipc": "^9.1.1",
"open": "^6.3.0",
"ora": "^3.4.0",
"read-pkg": "^5.1.1",
"request": "^2.88.2",
"request-promise-native": "^1.0.8",
"semver": "^6.1.0",
"strip-ansi": "^6.0.0"
}
},
"semver": {
"version": "6.3.0",
"resolved": "https://registry.npm.taobao.org/semver/download/semver-6.3.0.tgz?cache=0&sync_timestamp=1586534511518&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsemver%2Fdownload%2Fsemver-6.3.0.tgz",
"integrity": "sha1-7gpkyK9ejO6mdoexM3YeG+y9HT0=",
"dev": true
}
}
},
"@vue/cli-plugin-vuex": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/@vue/cli-plugin-vuex/-/cli-plugin-vuex-4.2.3.tgz",
"integrity": "sha512-7M4CaoAD4W/GdiDI4+Gh2tATPFBnb/u7bCiLLDsuL9ztypv7l3p4cu43zkDpTCCuufkZFYtZwysOAY8SbGqOjg==",
"version": "4.3.1",
"resolved": "https://registry.npm.taobao.org/@vue/cli-plugin-vuex/download/@vue/cli-plugin-vuex-4.3.1.tgz",
"integrity": "sha1-K3Ov9W+eG+MQGIc9XtLVnxVedHY=",
"dev": true
},
"@vue/cli-service": {
@ -11290,6 +11319,11 @@
}
}
},
"vue-router": {
"version": "3.1.6",
"resolved": "https://registry.npm.taobao.org/vue-router/download/vue-router-3.1.6.tgz?cache=0&sync_timestamp=1586343646335&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fvue-router%2Fdownload%2Fvue-router-3.1.6.tgz",
"integrity": "sha1-RfWjo4Q+MXAsBh3YKTk1VOQyj4k="
},
"vue-style-loader": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/vue-style-loader/-/vue-style-loader-4.1.2.tgz",
@ -11338,6 +11372,11 @@
"loader-utils": "^1.2.0"
}
},
"vuex": {
"version": "3.1.3",
"resolved": "https://registry.npm.taobao.org/vuex/download/vuex-3.1.3.tgz?cache=0&sync_timestamp=1584268708627&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fvuex%2Fdownload%2Fvuex-3.1.3.tgz",
"integrity": "sha1-8q1z4/tzaRaYs4yT9m5Y4meUcYA="
},
"watchpack": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.6.0.tgz",

@ -12,12 +12,16 @@
"jquery": "^3.4.1",
"pdfjs-dist": "^2.3.200",
"vue": "^2.6.11",
"vue-router": "^3.1.6",
"vuetify": "^2.2.11",
"vuex": "^3.1.3",
"webrtc-adapter": "^7.5.1"
},
"devDependencies": {
"@vue/cli-plugin-babel": "~4.2.0",
"@vue/cli-plugin-eslint": "~4.2.0",
"@vue/cli-plugin-router": "^4.3.1",
"@vue/cli-plugin-vuex": "^4.3.1",
"@vue/cli-service": "~4.2.0",
"axios": "^0.18.0",
"babel-eslint": "^10.0.3",

@ -1,36 +1,7 @@
<template>
<v-app fill-height dark>
<v-content fill-height >
<v-text-field v-if="!start" v-model="username" label="please enter name"></v-text-field> <v-btn v-if="!start" @click="startM">Start</v-btn>
<VueJanus v-if="start" server="https://vid.w3ic.org/janus" :room="room" :username="username"/>
</v-content>
</v-app>
<v-app>
<v-content>
<router-view></router-view>
</v-content></v-app>
</template>
<script>
import VueJanus from "@/lib/VueJanus";
export default {
name: 'App',
components: {
VueJanus
},
data: () => ({
test: ' ',
room:1234,
username: '',
start:false
}),
mounted () {
},
methods: {
startM () {
if (this.username) {
this.start = true
}
}
}
};
</script>

@ -1,5 +1,6 @@
<template>
<v-card max-height="150" height="150" dark
:color="remoteStream.talking?'green':''"
class="vid_main" @mouseleave="showaction = false" @mouseover="showaction = true">
<video ref="feed_video" class="vid_container" autoplay playsinline/>
<div class="infor">{{ bitrate }}</div>
@ -87,6 +88,7 @@
this.$refs.feed_video.src = URL.createObjectURL(stream)
}
this.$refs
} else {
console.log(this.$refs.feed_video)
}
@ -96,6 +98,7 @@
this.bitrate = this.remoteFeed.getBitrate()
},
feedResponse (jsep) {
console.log(jsep)
var body = { "request": "start", "room": this.room }
this.remoteFeed.send({"message": body, "jsep": jsep})
},
@ -108,7 +111,6 @@
if (msg["janus"]) {
console.log("######################")
console.log("nn",msg)
}
console.log("-------------------------")
var event = msg["videoroom"];
@ -117,7 +119,6 @@
} else if(event !== undefined && event != null) {
this.remoteFeed.rfid = msg["id"]
this.remoteFeed.rfdisplay = msg["display"]
} else if(event === "event") {
var substream = msg["substream"]
var temporal = msg["temporal"]

@ -1,7 +1,6 @@
<template>
<v-container fill-height>
<PdfShare v-if="sharePdf" :username="username" :opaque-id="opaqueId" :room="room" :janus-init="janusInit" ></PdfShare>
<PdfShare v-if="sharePdf" :username="username" :opaque-id="opaqueId" :room="room" :janus-init="janusInit" ></PdfShare>
<v-dialog
v-model="mozillaAlert"
max-width="600"
@ -89,15 +88,19 @@
<v-row>
<v-col cols="12" md="2">
<video ref="ownstream" class="rounded centered" id="myvideo" width="100%" height="100%" autoplay
playsinline muted="muted"/>
<div width="100%" height="100%" style="position: relative">
<video ref="ownstream" class="rounded centered" id="myvideo" width="100%" height="100%" autoplay
playsinline muted="muted"/>
<v-btn icon v-if="ownmuted" @click="muteMe"><v-icon>mdi-volume-mute</v-icon></v-btn>
<v-btn icon v-if="!ownmuted" @click="muteMe"><v-icon>mdi-volume-high</v-icon></v-btn>
</div>
</v-col>
<v-col cols="12" md="2" style="display: none">
<video ref="ownstreamscreen" class="rounded centered" id="myvideo2" width="100%" height="100%" autoplay
playsinline muted="muted"/>
</v-col>
<v-col cols="12" md="2" v-for="remoteStream in remoteStreams" :key="remoteStream.id">
<RemoteFeed :opaqueId="opaqueId" :mypvtid="mypvtid" :feedid="remoteStream.id" :remote-stream="remoteStream" :janusInit="janusInit" :room="room" ></RemoteFeed>
<RemoteFeed @kick="kickUser" :creator="creator" :talking="remoteStream.talking" :opaqueId="opaqueId" :mypvtid="mypvtid" :feedid="remoteStream.id" :remote-stream="remoteStream" :janusInit="janusInit" :room="room" ></RemoteFeed>
</v-col>
</v-row>
<v-speed-dial
@ -130,7 +133,7 @@
@click="sharePdf=true"
>
<v-icon>mdi-pdf-box</v-icon>
</v-btn>
</v-btn>
</template>
<span>Toggle Share PDF</span>
@ -151,7 +154,7 @@
<span>Toggle Theme</span>
</v-tooltip>
<v-tooltip right>
<template v-slot:activator="{ on }">
<v-btn
@ -168,7 +171,7 @@
<span>Toggle Camera</span>
</v-tooltip>
<v-tooltip right>
<template v-slot:activator="{ on }">
<v-btn
@ -196,7 +199,8 @@
props: {
server: String,
room: Number,
username: String
username: String,
creator: Boolean
},
data() {
return {
@ -205,6 +209,7 @@
pluginHandle: null,
mystream: null,
myid: '',
ownmuted: false,
mypvtid: '',
selectedVideo: null,
selectedAudio: null,
@ -240,11 +245,24 @@
},
methods: {
kickUser (user) {
this.$emit('kick',user)
},
muteMe () {
this.ownmuted = !this.ownmuted
if(!this.ownmuted) {
this.pluginHandle.unmuteAudio()
} else {
this.pluginHandle.muteAudio()
}
},
stopSharePdf(){
this.sharePdf=false;
},
webrtcState (on) {
this.pluginHandle.send({"message": { "request": "configure", "bitrate": 512*1000 }});
this.pluginHandle.send({"message": { "request": "configure", "bitrate": 128*1000 }});
console.log(on, "webrt")
},
janusPluginSuccessScreen (pluginHandle) {
@ -349,7 +367,6 @@
this.$janus.listDevices(this.initDevices);
},
initDevices (devices) {
console.log(devices)
@ -371,13 +388,14 @@
},
offerSend (jsep) {
console.log('vid offer')
console.log(jsep)
var publish = {"request": "configure", "audio": true, "video": true};
this.pluginHandle.send({"message": publish, "jsep": jsep});
},
controlPublishers(msg) {
msg["publishers"].forEach(item => {
var has = false
item.talking = false
this.remoteStreams.forEach(rm => {
if (item.id === rm.id) has = true
})
@ -390,7 +408,19 @@
janusMessage (msg, jsep) {
console.log(msg);
var event = msg["videoroom"];
if (event !== undefined) {
if (event === "talking") {
this.remoteStreams.forEach(item => {
if (item.id === msg['id']) item.talking = true
})
}
if (event === "stopped-talking") {
this.remoteStreams.forEach(item => {
if (item.id === msg['id']) item.talking = false
})
}
if (event === "joined") {
this.myid = msg["id"];
this.mypvtid = msg["private_id"];

@ -3,12 +3,15 @@ import './plugins/axios'
import JanusPlugin from "@/plugins/janus"
import App from './App.vue'
import vuetify from './plugins/vuetify';
import router from './router'
import store from './store'
Vue.config.productionTip = false
console.log("janus is installed", Vue.$janus)
new Vue({
vuetify,
JanusPlugin,
router,
store,
render: h => h(App)
}).$mount('#app')

@ -9,7 +9,7 @@ import axios from "axios";
// axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
let config = {
// baseURL: process.env.baseURL || process.env.apiUrl || ""
baseURL: process.env.baseURL || process.env.apiUrl || "http://localhost:5000/api/"
// timeout: 60 * 1000, // Timeout
// withCredentials: true, // Check cross-site Access-Control
};

@ -0,0 +1,34 @@
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
const routes = [
{
path: '/login',
name: 'login',
component: () => import(/* webpackChunkName: "login" */ '../views/login.vue')
}, {
path: '/',
name: 'Home',
component: () => import(/* webpackChunkName: "Home" */ '../views/Home.vue')
},
{
path: '/rooms',
name: 'Room',
component: () => import(/* webpackChunkName: "Room" */ '../views/Room.vue')
},
{
path: '/room/:id',
name: 'RoomView',
component: () => import(/* webpackChunkName: "RoomView" */ '../views/RoomView.vue')
}
]
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
export default router

@ -0,0 +1,17 @@
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
token: null,
name: 'None'
},
mutations: {
},
actions: {
},
modules: {
}
})

@ -0,0 +1,19 @@
<template>
<v-container>
<v-text-field v-model="room" label="Enter Room Name"></v-text-field> <v-btn @click="$router.push('/room/' + this.room)">Enter Room</v-btn><br />
<v-btn x-small @click="$router.push('/login')" text>login with user</v-btn>
</v-container>
</template>
<script>
export default {
name: "Home",
data: () => ({
room: null
})
}
</script>
<style scoped>
</style>

@ -0,0 +1,83 @@
<template>
<v-container>
<v-dialog
v-model="createDialog"
max-width="290"
>
<v-card>
<v-card-title>
<v-row>
<v-col cols="12"><v-text-field v-model="roomCreate.room_name" placeholder="name"></v-text-field></v-col>
<v-col cols="12"><v-text-field v-model="roomCreate.publisher_count" placeholder="Room Publisher Count"></v-text-field></v-col>
<v-col cols="12"><v-select label="Video Codec" v-model="roomCreate.video_codec" :items="vcodecs"></v-select></v-col>
<v-col cols="12"><v-select label="Audio Codec" v-model="roomCreate.audio_codec" :items="acodecs"></v-select></v-col>
</v-row>
</v-card-title>
<v-card-actions>
<v-btn @click="createDialog=false">Cancel</v-btn>
<v-spacer></v-spacer>
<v-btn @click="saveRoom">Create</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
<v-btn v-if="canCreate" @click="createDialog=true">Create Room</v-btn>
<v-row>
<v-col v-for="room in rooms" :key="room.id" cols="12">
<v-btn @click="joinRoom(room.ridn)" text>{{ room.room_name }}</v-btn>
</v-col>
</v-row>
</v-container>
</template>
<script>
export default {
name: "Room",
data: () => ({
rooms: [],
canCreate: false,
createDialog: false,
vcodecs: ['VP8','VP9','h264'],
acodecs: ['OPUS'],
roomCreate: {
video_codec: 'VP9',
audio_codec: 'OPUS',
publisher_count: 16,
room_name: ''
}
}),
mounted () {
this.getRooms()
},
methods: {
saveRoom () {
this.$axios.post('create/room',this.roomCreate).then(response => {
this.roomCreate ={
video_codec: 'VP9',
audio_codec: 'OPUS',
publisher_count: 16,
room_name: ''
}
this.getRooms()
this.createDialog = false
console.log(response)
})
},
joinRoom (id) {
this.$router.push('/room/' + id)
},
getRooms() {
this.$axios.get('rooms').then(response => {
console.log(response)
this.rooms = response.data.rooms
this.canCreate = response.data.can_create
}).catch(() => {
this.$router.push('/')
})
}
}
}
</script>
<style scoped>
</style>

@ -0,0 +1,59 @@
<template>
<div fill-height class="fill-height">
<v-dialog
v-model="dialog"
max-width="290"
>
<v-card>
<v-card-title class="headline">
What's your name ?
</v-card-title>
<v-card-text>
<v-text-field label="Name" v-model="name"></v-text-field>
</v-card-text>
<v-card-actions>
<v-btn @click="dialog=false" text>Cancel</v-btn>
<v-spacer></v-spacer>
<v-btn @click="getRoom" color="primary" text>Enter Room</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
<VueJanus @kick="kick" v-if="rid" :creator="creator" :room="rid" server="wss://vid.w3ic.org/ws/janus/" :username="name"></VueJanus>
</div>
</template>
<script>
import VueJanus from "@/lib/VueJanus";
export default {
name: "RoomView",
components: {VueJanus},
data: () => ({
rid:'',
name:'',
dialog:false,
creator:false
}),
mounted () {
if (!name) this.dialog = true
},
methods: {
kick (user) {
this.$axios.get(`kick/${this.$route.params.id}/${user}`).then(response => {
console.log(response)
})
},
getRoom () {
this.dialog = false
this.$axios.get(`room/${this.$route.params.id}`).then(response => {
this.rid = response.data.rid
this.creator = response.data.can_modify
})
}
}
}
</script>
<style scoped>
</style>

@ -0,0 +1,51 @@
<template>
<v-container>
<v-row>
<v-col cols="12" md="12" sm="12" v-if="error">
<v-alert type="error">{{error}}</v-alert>
</v-col>
<v-col cols="12" md="6" sm="12">
<v-text-field placeholder="Name/Nickname" v-model="name"></v-text-field>
</v-col>
<v-col cols="12" md="6" sm="12">
<v-text-field placeholder="Code" v-model="code"></v-text-field>
</v-col>
<v-col cols="12" md="12" sm="12">
<v-text-field v-if="passwd" v-model="password" placeholder="Password" type="password"></v-text-field>
</v-col>
<v-col cols="12" md="6" sm="12"><v-btn @click="passwd=!passwd" text>Password Login</v-btn></v-col>
<v-col cols="12" md="6" sm="12">
<v-btn @click="login">Login</v-btn>
</v-col>
</v-row>
</v-container>
</template>
<script>
export default {
name: 'Home',
data:() => ({
passwd: false,
name:'',
code:'',
error:'',
password:''
}),
methods: {
login () {
this.$axios.post('login', {
username: this.code,
password: this.password
}).then(response => {
this.$store.state.token = response.data.access_token
this.$axios.defaults.headers.common['Authorization'] = "Bearer " + response.data.access_token
this.$store.state.name = this.name
this.$router.push('/rooms')
}).catch((resp) => {
this.error = resp.response.data.msg
})
}
}
}
</script>
Loading…
Cancel
Save