parent
ae544add07
commit
3c87a375c3
After Width: | Height: | Size: 539 B |
@ -0,0 +1,124 @@ |
||||
<template> |
||||
<div class="vid_main"> |
||||
<video ref="feed_video" width="100%" height="100%" autoplay playsinline/> |
||||
<div class="info">{{ bitrate }}</div> |
||||
<div class="actions"></div> |
||||
</div> |
||||
|
||||
</template> |
||||
|
||||
<script> |
||||
export default { |
||||
props: { |
||||
janusInit: Object, |
||||
opaqueId: String, |
||||
room: Number, |
||||
mypvtid: String, |
||||
feedid: String |
||||
}, |
||||
name: "RemoteFeed", |
||||
data: () => ({ |
||||
remoteFeed: null, |
||||
bitrateTimer: null, |
||||
bitrate: 0 |
||||
}), |
||||
mounted () { |
||||
console.log(this.janusInit) |
||||
this.janusInit.attach({ |
||||
plugin: "janus.plugin.videoroom", |
||||
opaqueId: this.opaqueId, |
||||
success: this.onSuccess, |
||||
onmessage: this.onMessage, |
||||
error: function(error) { |
||||
console.log(" -- Error attaching plugin...", error); |
||||
// bootbox.alert("Error attaching plugin... " + error); |
||||
}, |
||||
webrtcState: function(on) { |
||||
console.log("Janus says this WebRTC PeerConnection " + (on ? "up" : "down") + " now"); |
||||
}, |
||||
onlocalstream: this.onlocalstream, |
||||
onremotestream: this.onStream |
||||
|
||||
}) |
||||
}, |
||||
methods: { |
||||
onSuccess (pluginHandle) { |
||||
this.remoteFeed = pluginHandle; |
||||
this.remoteFeed.simulcastStarted = false; |
||||
console.log('Remote feed success') |
||||
var subscribe = { "request": "join", "room": this.room, "ptype": "subscriber", "feed": this.feedid, "private_id": this.mypvtid }; |
||||
|
||||
this.remoteFeed.send({"message": subscribe}); |
||||
|
||||
}, |
||||
onlocalstream (locals) { |
||||
console.log(locals) |
||||
}, |
||||
onStream (stream) { |
||||
console.log('stream is strarted') |
||||
|
||||
this.$refs.feed_video.srcObject = stream |
||||
setInterval(() => { |
||||
this.bitrate = this.remoteFeed.getBitrate() |
||||
},1000) |
||||
}, |
||||
feedResponse (jsep) { |
||||
var body = { "request": "start", "room": this.room } |
||||
this.remoteFeed.send({"message": body, "jsep": jsep}) |
||||
}, |
||||
feedError (error) { |
||||
console.log("WebRTC error:", error) |
||||
}, |
||||
onMessage (msg, jsep) { |
||||
console.log(msg) |
||||
console.log(jsep) |
||||
console.log("-------------------------") |
||||
var event = msg["videoroom"]; |
||||
if(msg["error"] !== undefined && msg["error"] !== null) { |
||||
console.log(msg["error"]); |
||||
} 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"] |
||||
console.log(substream,temporal) |
||||
} |
||||
if(jsep !== undefined && jsep !== null) { |
||||
console.log('jsep') |
||||
console.log(jsep) |
||||
this.remoteFeed.createAnswer( |
||||
{ |
||||
jsep: jsep, |
||||
// Add data:true here if you want to subscribe to datachannels as well |
||||
// (obviously only works if the publisher offered them in the first place) |
||||
media: { audioSend: false, videoSend: false }, // We want recvonly audio/video |
||||
success: this.feedResponse, |
||||
error: this.feedError |
||||
}); |
||||
} |
||||
}, |
||||
onError (error) { |
||||
console.log(error) |
||||
} |
||||
} |
||||
|
||||
} |
||||
</script> |
||||
|
||||
<style scoped> |
||||
.actions { |
||||
position: absolute; |
||||
bottom:0; |
||||
left:0; |
||||
} |
||||
.vid_main { |
||||
position: relative; |
||||
} |
||||
.info { |
||||
position: absolute; |
||||
right: 0; |
||||
top:0; |
||||
} |
||||
</style> |
@ -0,0 +1,279 @@ |
||||
<template> |
||||
<v-container> |
||||
<v-dialog |
||||
v-model="deviceSelectDialog" |
||||
max-width="290" |
||||
> |
||||
<v-card> |
||||
<v-card-title class="headline">Configuration</v-card-title> |
||||
|
||||
<v-card-text> |
||||
<v-row> |
||||
<v-col md="12" cols="12"> |
||||
<v-select |
||||
label="Please select video device" |
||||
v-model="selectedVideo" |
||||
:items="videoDevices" |
||||
item-value="deviceId" |
||||
item-text="label" |
||||
></v-select> |
||||
</v-col> |
||||
<v-col md="12" cols="12"> |
||||
<v-select |
||||
label="Please select audio device" |
||||
:items="audioDevices" |
||||
v-model="selectedAudio" |
||||
item-value="deviceId" |
||||
item-text="label" |
||||
></v-select> |
||||
</v-col> |
||||
</v-row> |
||||
</v-card-text> |
||||
|
||||
<v-card-actions> |
||||
<v-spacer></v-spacer> |
||||
|
||||
<v-btn |
||||
color="green darken-1" |
||||
text |
||||
@click="deviceSelectDialog = false" |
||||
> |
||||
Disagree |
||||
</v-btn> |
||||
|
||||
<v-btn |
||||
color="green darken-1" |
||||
text |
||||
@click="selectDevice" |
||||
> |
||||
Agree |
||||
</v-btn> |
||||
</v-card-actions> |
||||
</v-card> |
||||
</v-dialog> |
||||
<v-btn @click="genRemoteFeed">Remote Feed</v-btn> |
||||
<v-row> |
||||
<v-col cols="12" md="3"> |
||||
<video ref="ownstream" class="rounded centered" id="myvideo" width="100%" height="100%" autoplay |
||||
playsinline muted="muted"/> |
||||
</v-col> |
||||
<v-col cols="12" md="3" v-for="remoteStream in remoteStreams" :key="remoteStream.id"> |
||||
<RemoteFeed :opaqueId="opaqueId" :mypvtid="mypvtid" :feedid="remoteStream.id" :janusInit="janusInit" :room="room" ></RemoteFeed> |
||||
</v-col> |
||||
</v-row> |
||||
</v-container> |
||||
</template> |
||||
|
||||
<script> |
||||
|
||||
|
||||
import RemoteFeed from "@/lib/RemoteFeed"; |
||||
export default { |
||||
components: {RemoteFeed}, |
||||
props: { |
||||
server: String, |
||||
room: Number, |
||||
username: String |
||||
}, |
||||
data() { |
||||
return { |
||||
janusInit: null, |
||||
opaqueId: null, |
||||
pluginHandle: null, |
||||
mystream: null, |
||||
myid: '', |
||||
mypvtid: '', |
||||
selectedVideo: null, |
||||
selectedAudio: null, |
||||
videoDevices: [], |
||||
audioDevices: [], |
||||
deviceSelectDialog: false, |
||||
remoteStreams: [] |
||||
} |
||||
}, |
||||
name: "VueJanus", |
||||
mounted() { |
||||
this.janusInit = new this.$janus({ |
||||
success: this.janusSuccess, |
||||
server: this.server, |
||||
error: function (error) { |
||||
this.$janus.error(error); |
||||
}, |
||||
destroyed: function () { |
||||
window.location.reload(); |
||||
} |
||||
}) |
||||
|
||||
}, |
||||
methods: { |
||||
janusPluginError: function (error) { |
||||
console.log(error) |
||||
}, |
||||
consentDialog: function (on) { |
||||
// this.$janus.debug("Consent dialog should be " + (on ? "on" : "off") + " now"); |
||||
console.log(on) |
||||
}, |
||||
janusPluginSuccess: function (pluginHandle) { |
||||
this.pluginHandle = pluginHandle |
||||
this.$janus.log("Plugin attached! (" + this.pluginHandle.getPlugin() + ", id=" + this.pluginHandle.getId() + ")"); |
||||
this.$janus.log(" -- This is a publisher/manager"); |
||||
|
||||
this.$janus.listDevices(this.initDevices); |
||||
|
||||
|
||||
}, |
||||
initDevices: function (devices) { |
||||
console.log(devices) |
||||
devices.forEach(device => { |
||||
if (device.kind === 'videoinput') { |
||||
this.videoDevices.push(device) |
||||
} |
||||
if (device.kind === 'audioinput') { |
||||
this.audioDevices.push(device) |
||||
} |
||||
|
||||
}) |
||||
this.deviceSelectDialog = true |
||||
}, |
||||
genRemoteFeed: function () { |
||||
this.remoteStreams.forEach(item => { |
||||
this.createRemoteFeed(item) |
||||
}) |
||||
}, |
||||
offerSend: function (jsep) { |
||||
console.log('vid offer') |
||||
var publish = {"request": "configure", "audio": true, "video": true}; |
||||
|
||||
this.pluginHandle.send({"message": publish, "jsep": jsep}); |
||||
}, |
||||
controlPublishers: function(msg) { |
||||
msg["publishers"].forEach(item => { |
||||
var has = false |
||||
this.remoteStreams.forEach(rm => { |
||||
if (item.id === rm.id) has = true |
||||
}) |
||||
if (!has) { |
||||
this.remoteStreams.push(item) |
||||
} |
||||
|
||||
}) |
||||
}, |
||||
janusMessage: function (msg, jsep) { |
||||
// this.$janus.debug(" ::: Got a message (publisher) :::"); |
||||
console.log(msg); |
||||
// this.$janus.debug(jsep); |
||||
var event = msg["videoroom"]; |
||||
// this.$janus.debug("Event: " + event); |
||||
if (event !== undefined) { |
||||
if (event === "joined") { |
||||
this.myid = msg["id"]; |
||||
this.mypvtid = msg["private_id"]; |
||||
this.$janus.log("Successfully joined room " + msg["room"] + " with ID " + this.myid); |
||||
this.restartDevices() |
||||
if (msg["publishers"] !== undefined && msg["publishers"] !== null) { |
||||
this.controlPublishers(msg) |
||||
} |
||||
} else if(event === "event") { |
||||
// Any new feed to attach to? |
||||
if (msg["publishers"] !== undefined && msg["publishers"] !== null) { |
||||
this.controlPublishers(msg) |
||||
|
||||
} else if(msg["leaving"] !== undefined && msg["leaving"] !== null) { |
||||
console.log("leaving") |
||||
this.remoteStreams.forEach(item => { |
||||
if (item.id === msg['leaving']) this.remoteStreams.splice(this.remoteStreams.indexOf(item),1) |
||||
}) |
||||
} |
||||
} |
||||
} |
||||
if (jsep !== undefined && jsep !== null) { |
||||
|
||||
console.log("Handling SDP as well..."); |
||||
console.log(jsep); |
||||
this.pluginHandle.handleRemoteJsep({jsep: jsep}); |
||||
var audio = msg["audio_codec"]; |
||||
if (this.mystream && this.mystream.getAudioTracks() && this.mystream.getAudioTracks().length > 0 && !audio) { |
||||
// Audio has been rejected |
||||
//toastr.warning("Our audio stream has been rejected, viewers won't hear us"); |
||||
console.log("Our audio stream has been rejected, viewers won't hear us"); |
||||
} |
||||
} |
||||
}, |
||||
onlocalstream: function (stream) { |
||||
// this.$janus.debug(" ::: Got a local stream :::"); |
||||
// this.$janus.debug(stream); |
||||
this.mystream = stream |
||||
console.log(this.$refs) |
||||
console.log(this.$refs["ownstream"]) |
||||
this.$refs.ownstream.srcObject = this.mystream |
||||
|
||||
}, |
||||
restartDevices: function () { |
||||
this.deviceSelectDialog = false |
||||
|
||||
var media = { |
||||
audioRecv: false, videoRecv: false, audioSend: true, videoSend: true, |
||||
audio: { |
||||
deviceId: { |
||||
exact: this.selectedAudio |
||||
} |
||||
}, |
||||
replaceAudio: true, // This is only needed in case of a renegotiation |
||||
video: { |
||||
deviceId: { |
||||
exact: this.selectedVideo |
||||
} |
||||
}, |
||||
replaceVideo: true, |
||||
}; |
||||
|
||||
|
||||
this.pluginHandle.createOffer( |
||||
{ |
||||
media: media, |
||||
success: this.offerSend, |
||||
error: function (error) { |
||||
// An error has occurred ... |
||||
console.log(error) |
||||
} |
||||
}) |
||||
}, |
||||
webrtcState: function (on) { |
||||
this.$janus.log("Janus says our WebRTC PeerConnection is " + (on ? "up" : "down") + " now"); |
||||
}, |
||||
mediaState: function (medium, on) { |
||||
this.$janus.log("Janus " + (on ? "started" : "stopped") + " receiving our " + medium); |
||||
}, |
||||
selectDevice: function () { |
||||
console.log(this.selectedVideo) |
||||
console.log(this.selectedAudio) |
||||
// this.$refs.ownstream.setSinkId(this.selectedVideo) |
||||
// this.$refs.ownstream.setSinkId(this.selectedAudio) |
||||
|
||||
var register = {"request": "join", "room": this.room, "ptype": "publisher", "display": this.username}; |
||||
this.pluginHandle.send({"message": register}); |
||||
}, |
||||
janusSuccess: function () { |
||||
this.opaqueId = "videoroomtest-" + this.$janus.randomString(12); |
||||
|
||||
this.janusInit.attach( |
||||
{ |
||||
plugin: "janus.plugin.videoroom", |
||||
opaqueId: this.opaqueId, |
||||
success: this.janusPluginSuccess, |
||||
consentDialog: this.consentDialog, |
||||
error: this.janusPluginError, |
||||
mediaState: this.mediaState, |
||||
webrtcState: this.webrtcState, |
||||
onmessage: this.janusMessage, |
||||
onlocalstream: this.onlocalstream |
||||
} |
||||
) |
||||
} |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<style scoped> |
||||
|
||||
</style> |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,8 +1,14 @@ |
||||
import Vue from 'vue' |
||||
import './plugins/axios' |
||||
import JanusPlugin from "@/plugins/janus" |
||||
import App from './App.vue' |
||||
import vuetify from './plugins/vuetify'; |
||||
|
||||
Vue.config.productionTip = false |
||||
|
||||
Vue.config.productionTip = false |
||||
console.log("janus is installed", Vue.$janus) |
||||
new Vue({ |
||||
render: h => h(App), |
||||
vuetify, |
||||
JanusPlugin, |
||||
render: h => h(App) |
||||
}).$mount('#app') |
||||
|
@ -0,0 +1,62 @@ |
||||
"use strict"; |
||||
|
||||
import Vue from 'vue'; |
||||
import axios from "axios"; |
||||
|
||||
// Full config: https://github.com/axios/axios#request-config
|
||||
// axios.defaults.baseURL = process.env.baseURL || process.env.apiUrl || '';
|
||||
// axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
|
||||
// axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
|
||||
|
||||
let config = { |
||||
// baseURL: process.env.baseURL || process.env.apiUrl || ""
|
||||
// timeout: 60 * 1000, // Timeout
|
||||
// withCredentials: true, // Check cross-site Access-Control
|
||||
}; |
||||
|
||||
const _axios = axios.create(config); |
||||
|
||||
_axios.interceptors.request.use( |
||||
function(config) { |
||||
// Do something before request is sent
|
||||
return config; |
||||
}, |
||||
function(error) { |
||||
// Do something with request error
|
||||
return Promise.reject(error); |
||||
} |
||||
); |
||||
|
||||
// Add a response interceptor
|
||||
_axios.interceptors.response.use( |
||||
function(response) { |
||||
// Do something with response data
|
||||
return response; |
||||
}, |
||||
function(error) { |
||||
// Do something with response error
|
||||
return Promise.reject(error); |
||||
} |
||||
); |
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
Plugin.install = function(Vue, options) { |
||||
Vue.axios = _axios; |
||||
window.axios = _axios; |
||||
Object.defineProperties(Vue.prototype, { |
||||
axios: { |
||||
get() { |
||||
return _axios; |
||||
} |
||||
}, |
||||
$axios: { |
||||
get() { |
||||
return _axios; |
||||
} |
||||
}, |
||||
}); |
||||
}; |
||||
|
||||
Vue.use(Plugin) |
||||
|
||||
export default Plugin; |
@ -0,0 +1,21 @@ |
||||
"use strict"; |
||||
|
||||
import Vue from 'vue' |
||||
import Janus from "@/lib/janus" |
||||
const _janus = Janus |
||||
|
||||
const JanusPlugin = { |
||||
// eslint-disable-next-line no-unused-vars
|
||||
install(Vue, options) { |
||||
console.log('install call') |
||||
console.log(_janus) |
||||
_janus.init({debug: true, callback: function() { |
||||
Vue.prototype.$janus = _janus |
||||
}}) |
||||
} |
||||
} |
||||
|
||||
|
||||
|
||||
export default JanusPlugin; |
||||
Vue.use(JanusPlugin) |
@ -0,0 +1,23 @@ |
||||
import Vue from 'vue'; |
||||
import Vuetify from 'vuetify/lib'; |
||||
|
||||
Vue.use(Vuetify); |
||||
|
||||
export default new Vuetify({ |
||||
theme: { |
||||
options: { |
||||
customProperties: true, |
||||
}, |
||||
themes: { |
||||
light: { |
||||
primary: '#ee44aa', |
||||
secondary: '#424242', |
||||
accent: '#82B1FF', |
||||
error: '#FF5252', |
||||
info: '#2196F3', |
||||
success: '#4CAF50', |
||||
warning: '#FFC107' |
||||
}, |
||||
}, |
||||
}, |
||||
}); |
@ -0,0 +1,5 @@ |
||||
module.exports = { |
||||
"transpileDependencies": [ |
||||
"vuetify" |
||||
] |
||||
} |
Loading…
Reference in new issue