You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
projectx/src/lib/VueJanus.vue

508 lines
19 KiB

<template>
<v-container fill-height>
<PdfShare v-if="sharePdf" :username="username" :opaque-id="opaqueId" :room="room" :onstop="stopSharePdf" :janus-init="janusInit" ></PdfShare>
<v-dialog
v-model="mozillaAlert"
max-width="600"
>
<v-card>
<v-card-title class="headline">Share whole screen or a window?</v-card-title>
<v-card-text>
Firefox handles screensharing in a different way: are you going to share the whole screen, or would you rather pick a single window/application to share instead?
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn @click="shareScreenStart('screen')">Share a screen</v-btn>
<v-spacer></v-spacer>
<v-btn @click="shareScreenStart('window')">Share a window</v-btn>
<v-spacer></v-spacer>
</v-card-actions>
</v-card>
</v-dialog>
<v-dialog
v-model="chromeAlert"
max-width="600"
>
<v-card>
<v-card-title class="headline">Chrome Extension Error</v-card-title>
<v-card-text>
You're using Chrome but don't have the screensharing extension installed: click <b><a href='https://chrome.google.com/webstore/detail/janus-webrtc-screensharin/hapfgfdkleiggjjpfpenajgdnfckjpaj' target='_blank'>here</a></b> to do so
</v-card-text>
</v-card>
</v-dialog>
<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-checkbox label="No Video" v-model="noVid"></v-checkbox>
</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-row>
<v-col cols="12" md="2">
<video ref="ownstream" class="rounded centered" id="myvideo" width="100%" height="100%" autoplay
playsinline muted="muted"/>
</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>
</v-col>
</v-row>
<v-speed-dial
v-model="fab"
bottom
left
direction="top"
open-on-hover
>
<template v-slot:activator>
<v-btn
v-model="fab"
color="blue darken-2"
dark
fab
>
<v-icon v-if="fab">mdi-cog-outline</v-icon>
<v-icon v-else>mdi-cog-outline</v-icon>
</v-btn>
</template>
<v-tooltip right>
<template v-slot:activator="{ on }">
<v-btn
v-on="on"
fab
dark
small
@click="sharePdf=true"
>
<v-icon>mdi-pdf-box</v-icon>
</v-btn>
</template>
<span>Toggle Share PDF</span>
</v-tooltip>
<v-tooltip right>
<template v-slot:activator="{ on }">
<v-btn
v-on="on"
fab
dark
small
@click="$vuetify.theme.dark=!$vuetify.theme.dark"
>
<v-icon>mdi-compare</v-icon>
</v-btn>
</template>
<span>Toggle Theme</span>
</v-tooltip>
<v-tooltip right>
<template v-slot:activator="{ on }">
<v-btn
v-on="on"
fab
dark
small
@click="deviceSelectDialog = true"
>
<v-icon>mdi-camera-outline</v-icon>
</v-btn>
</template>
<span>Toggle Camera</span>
</v-tooltip>
<v-tooltip right>
<template v-slot:activator="{ on }">
<v-btn
v-on="on"
fab
:dark="!screenShareStarted"
small
@click="screenShareSwitch"
>
<v-icon>mdi-monitor-screenshot</v-icon>
</v-btn>
</template>
<span>Toggle Share Screen</span>
</v-tooltip>
</v-speed-dial>
</v-container>
</template>
<script>
import RemoteFeed from "@/lib/RemoteFeed";
import PdfShare from "@/lib/PdfShare";
export default {
components: {PdfShare, RemoteFeed},
props: {
server: String,
room: Number,
username: String
},
data() {
return {
janusInit: null,
opaqueId: null,
pluginHandle: null,
mystream: null,
myid: '',
mypvtid: '',
selectedVideo: null,
selectedAudio: null,
started: false,
mozillaAlert: false,
sharePdf: false,
janusScreenShareHandle: null,
chromeAlert: false,
videoDevices: [],
capture: '',
audioDevices: [],
deviceSelectDialog: false,
noVid: false,
fab: true,
shareScreenId: null,
remoteStreams: [],
screenShareStarted: false
}
},
name: "VueJanus",
mounted() {
this.janusInit = new this.$janus({
success: this.janusSuccess,
server: this.server,
error: function (error) {
this.$janus.error(error);
},
webrtcState: this.webrtcState,
destroyed: function () {
window.location.reload();
}
})
},
methods: {
stopSharePdf(){
this.sharePdf=false;
},
webrtcState (on) {
this.pluginHandle.send({"message": { "request": "configure", "bitrate": 512*1000 }});
console.log(on, "webrt")
},
janusPluginSuccessScreen (pluginHandle) {
this.janusScreenShareHandle = pluginHandle
this.$janus.log("Plugin attached! (" + this.pluginHandle.getPlugin() + ", id=" + this.pluginHandle.getId() + ")");
this.$janus.log(" -- This is a publisher/manager");
var register = { "request": "join", "room": this.room, "ptype": "publisher", "display": this.username + " - Share Screen" };
pluginHandle.send({"message": register});
},
castStart(jsep) {
var publish = { "request": "configure", "audio": false, "video": true };
this.janusScreenShareHandle.send({"message": publish, "jsep": jsep});
},
janusMessageScreen (msg, jesp) {
var event = msg["videoroom"]
console.log(jesp)
if(event === "joined") {
this.janusScreenShareHandle.createOffer(
{
media: { video: this.capture, audioSend: false, videoRecv: false}, // Screen sharing Publishers are sendonly
success: this.castStart,
error: function(error) {
console.log("WebRTC error:", error);
// bootbox.alert("WebRTC error... " + JSON.stringify(error));
}
});
}
if(jesp !== undefined && jesp !== null) {
// Janus.debug("Handling SDP as well...");
// Janus.debug(jsep);
this.janusScreenShareHandle.handleRemoteJsep({jsep: jesp});
}
},
onlocalstreamScreen (stream) {
if(this.screenShareStarted)
this.screenShareStarted=true;
this.$refs.ownstreamscreen.srcObject = stream
},
screenShareSwitch () {
if(this.screenShareStarted) {
this.screenShareStop()
} else {
this.screenShare()
}
},
shareScreenStart (capture) {
this.capture = capture
this.janusInit.attach(
{
plugin: "janus.plugin.videoroom",
opaqueId: this.opaqueId,
success: this.janusPluginSuccessScreen,
consentDialog: this.consentDialog,
error: this.janusPluginError,
mediaState: this.mediaState,
webrtcState: this.webrtcState,
onmessage: this.janusMessageScreen,
onlocalstream: this.onlocalstreamScreen
}
)
this.mozillaAlert=false;
this.chromeAlert=false;
},
screenShareStop(){
var srcObject=this.$refs.ownstreamscreen.srcObject;
for (const track of srcObject.getTracks()) {
track.stop();
}
var unpublish = { request: 'unpublish' };
this.janusScreenShareHandle.send({ message: unpublish });
this.janusScreenShareHandle.detach();
this.screenShareStarted=false;
},
screenShare () {
if(!this.$janus.isExtensionEnabled()) {
this.chromeAlert = true
return;
}
if(navigator.mozGetUserMedia) {
// Firefox needs a different constraint for screen and window sharing
this.mozillaAlert = true
return;
}
this.shareScreenStart('screen')
},
janusPluginError (error) {
console.log(error)
},
consentDialog (on) {
// this.$janus.debug("Consent dialog should be " + (on ? "on" : "off") + " now");
console.log(on)
},
janusPluginSuccess (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 (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 () {
this.remoteStreams.forEach(item => {
this.createRemoteFeed(item)
})
},
offerSend (jsep) {
console.log('vid offer')
var publish = {"request": "configure", "audio": true, "video": true};
this.pluginHandle.send({"message": publish, "jsep": jsep});
},
controlPublishers(msg) {
msg["publishers"].forEach(item => {
var has = false
this.remoteStreams.forEach(rm => {
if (item.id === rm.id) has = true
})
if (!has) {
if (this.username + " - Share Screen" !== item.display) this.remoteStreams.push(item)
}
})
},
janusMessage (msg, jsep) {
console.log(msg);
var event = msg["videoroom"];
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") {
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) {
console.log("Our audio stream has been rejected, viewers won't hear us");
}
}
},
onlocalstream (stream) {
this.mystream = stream
console.log(this.$refs)
console.log(this.$refs["ownstream"])
this.$refs.ownstream.srcObject = this.mystream
},
restartDevices () {
this.deviceSelectDialog = false
var media = {
audioRecv: false, videoRecv: false, audioSend: true, videoSend: !this.noVid,
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)
}
})
},
mediaState (medium, on) {
this.$janus.log("Janus " + (on ? "started" : "stopped") + " receiving our " + medium);
},
changeDevice () {
this.$refs.ownstream.setSinkId(this.selectedVideo)
this.$refs.ownstream.setSinkId(this.selectedAudio)
},
selectDevice () {
if (!this.started) {
console.log(this.selectedVideo)
console.log(this.selectedAudio)
this.started = true
var register = {
"request": "join",
"room": this.room,
"ptype": "publisher",
"display": this.username
};
this.pluginHandle.send({"message": register});
} else {
this.restartDevices()
}
},
janusSuccess () {
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>