Change-Id: I1d8ae9dc2b241c392e450d02c3aa5eeab7eabd50pull/13/head
parent
9da0c00285
commit
73ba4fa869
@ -1,219 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div
|
|
||||||
class="col-xs-10 col-sm-8 col-md-4 csc-opt-center"
|
|
||||||
>
|
|
||||||
<csc-inline-alert-info
|
|
||||||
v-if="!hasRtcEngineCapabilityEnabled"
|
|
||||||
class="q-mb-lg"
|
|
||||||
>
|
|
||||||
{{ $t('You can not join a conference, since the RTC:engine is not active. If you operate a C5 CE then first upgrade to a C5 PRO to be able to use the RTC:engine.') }}
|
|
||||||
</csc-inline-alert-info>
|
|
||||||
<div
|
|
||||||
class="text-h6 text-center q-mb-lg"
|
|
||||||
>
|
|
||||||
{{ $t('Join conference with name') }}
|
|
||||||
</div>
|
|
||||||
<q-input
|
|
||||||
ref="conferenceName"
|
|
||||||
class="q-mb-lg"
|
|
||||||
:value="conferenceIdInput"
|
|
||||||
:placeholder="$t('Conference name')"
|
|
||||||
:disable="isJoining || !hasRtcEngineCapabilityEnabled"
|
|
||||||
@input="conferenceIdChanged"
|
|
||||||
>
|
|
||||||
<template
|
|
||||||
v-slot:prepend
|
|
||||||
>
|
|
||||||
<q-icon
|
|
||||||
name="meeting_room"
|
|
||||||
size="24px"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
<template
|
|
||||||
v-slot:append
|
|
||||||
>
|
|
||||||
<q-btn
|
|
||||||
:disable="!hasConferenceId || isJoining || !hasRtcEngineCapabilityEnabled"
|
|
||||||
:color="shareButtonColor"
|
|
||||||
:label="$t('Share')"
|
|
||||||
flat
|
|
||||||
dense
|
|
||||||
icon="link"
|
|
||||||
@click="showShareDialog"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
</q-input>
|
|
||||||
<div
|
|
||||||
class="row justify-center"
|
|
||||||
>
|
|
||||||
<q-btn
|
|
||||||
:color="joinButtonColor"
|
|
||||||
:disable="!hasConferenceId || isJoining || !hasRtcEngineCapabilityEnabled"
|
|
||||||
icon="login"
|
|
||||||
text-color="dark"
|
|
||||||
unelevated
|
|
||||||
round
|
|
||||||
size="large"
|
|
||||||
@click="join"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<csc-object-spinner
|
|
||||||
:loading="isJoining"
|
|
||||||
/>
|
|
||||||
<csc-share-conference-dialog
|
|
||||||
ref="shareDialog"
|
|
||||||
:conference-url="conferenceUrl"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import {
|
|
||||||
randInRange
|
|
||||||
} from 'src/helpers/math-helper'
|
|
||||||
import CscShareConferenceDialog from './CscShareConferenceDialog'
|
|
||||||
import CscObjectSpinner from '../../CscObjectSpinner'
|
|
||||||
import CscInlineAlertInfo from 'components/CscInlineAlertInfo'
|
|
||||||
import { showGlobalError } from 'src/helpers/ui'
|
|
||||||
import { mapState } from 'vuex'
|
|
||||||
export default {
|
|
||||||
name: 'CscConferenceJoin',
|
|
||||||
components: {
|
|
||||||
CscInlineAlertInfo,
|
|
||||||
CscObjectSpinner,
|
|
||||||
CscShareConferenceDialog
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
conferenceId: {
|
|
||||||
type: String,
|
|
||||||
default: null
|
|
||||||
},
|
|
||||||
hasConferenceId: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
conferenceUrl: {
|
|
||||||
type: String,
|
|
||||||
default: null
|
|
||||||
},
|
|
||||||
localMediaStream: {
|
|
||||||
type: MediaStream,
|
|
||||||
default: null
|
|
||||||
},
|
|
||||||
isMicrophoneEnabled: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
isCameraEnabled: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
isScreenEnabled: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
isJoining: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
isJoined: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
hasRtcEngineCapabilityEnabled: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
data () {
|
|
||||||
return {
|
|
||||||
conferenceIdInput: this.conferenceId
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
...mapState('conference', [
|
|
||||||
'localMediaError'
|
|
||||||
]),
|
|
||||||
contentClasses () {
|
|
||||||
const classes = ['col', 'col-md-4', 'text-center']
|
|
||||||
if (this.isCameraEnabled) {
|
|
||||||
classes.push('csc-camera-background')
|
|
||||||
} else if (this.isScreenEnabled) {
|
|
||||||
classes.push('csc-screen-background')
|
|
||||||
}
|
|
||||||
return classes
|
|
||||||
},
|
|
||||||
joinButtonColor () {
|
|
||||||
return 'primary'
|
|
||||||
},
|
|
||||||
shareButtonColor () {
|
|
||||||
if (this.hasConferenceId) {
|
|
||||||
return 'primary'
|
|
||||||
} else {
|
|
||||||
return 'grey'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
isMediaEnabled () {
|
|
||||||
return this.isCameraEnabled || this.isScreenEnabled || this.isMicrophoneEnabled
|
|
||||||
}
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
conferenceId (value) {
|
|
||||||
this.conferenceIdInput = value
|
|
||||||
},
|
|
||||||
localMediaError (error) {
|
|
||||||
if (error !== null && error !== undefined) {
|
|
||||||
showGlobalError(error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mounted () {
|
|
||||||
if (!this.conferenceId) {
|
|
||||||
this.conferenceIdChanged(this.createConferenceId())
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
join () {
|
|
||||||
this.$emit('join', this.conferenceId)
|
|
||||||
},
|
|
||||||
conferenceIdChanged (value) {
|
|
||||||
try {
|
|
||||||
this.$router.push({
|
|
||||||
path: '/conference/' + value
|
|
||||||
})
|
|
||||||
this.conferenceIdInput = value
|
|
||||||
} catch (err) {
|
|
||||||
this.conferenceIdInput = this.conferenceId
|
|
||||||
}
|
|
||||||
},
|
|
||||||
showShareDialog () {
|
|
||||||
this.$refs.shareDialog.open()
|
|
||||||
},
|
|
||||||
createConferenceId () {
|
|
||||||
const prefixes = ['conf', 'room', 'space']
|
|
||||||
const randPrefixIndex = randInRange(0, prefixes.length - 1)
|
|
||||||
const randSuffix = randInRange(100000, 999999)
|
|
||||||
return prefixes[randPrefixIndex] + randSuffix
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="stylus" rel="stylesheet/stylus">
|
|
||||||
.csc-conf-alert
|
|
||||||
margin-bottom $flex-gutter-md
|
|
||||||
#csc-conf-link-input
|
|
||||||
margin-bottom $flex-gutter-md
|
|
||||||
#csc-conf-join-text
|
|
||||||
margin-bottom $flex-gutter-md
|
|
||||||
font-weight bold
|
|
||||||
font-size 1rem
|
|
||||||
#csc-conf-join-content
|
|
||||||
padding $flex-gutter-md
|
|
||||||
position relative
|
|
||||||
z-index 2
|
|
||||||
#csc-conf-join-content.csc-camera-background
|
|
||||||
background-color alpha($main-menu-background, 0.5)
|
|
||||||
#csc-conf-join-content.csc-screen-background
|
|
||||||
background-color alpha($main-menu-background, 0.5)
|
|
||||||
</style>
|
|
@ -1,15 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div />
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
name: 'CscConferenceJoined',
|
|
||||||
data () {
|
|
||||||
return {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="stylus" rel="stylesheet/stylus">
|
|
||||||
</style>
|
|
@ -1,95 +0,0 @@
|
|||||||
<template>
|
|
||||||
<q-card
|
|
||||||
class="bg-transparent"
|
|
||||||
flat
|
|
||||||
>
|
|
||||||
<q-card-section
|
|
||||||
v-if="!localMediaStream || localMediaStream && (!isCameraEnabled && !isScreenEnabled)"
|
|
||||||
class="bg-black text-center"
|
|
||||||
style="height: 100px"
|
|
||||||
>
|
|
||||||
<q-avatar
|
|
||||||
class="absolute-center"
|
|
||||||
style="top: 40px"
|
|
||||||
>
|
|
||||||
<q-icon
|
|
||||||
name="person"
|
|
||||||
size="32px"
|
|
||||||
/>
|
|
||||||
</q-avatar>
|
|
||||||
</q-card-section>
|
|
||||||
<q-card-section
|
|
||||||
v-show="localMediaStream && (isCameraEnabled || isScreenEnabled)"
|
|
||||||
class="relative-position bg-black text-center full-width no-padding"
|
|
||||||
style="height: 100px"
|
|
||||||
>
|
|
||||||
<csc-media
|
|
||||||
ref="cscMedia"
|
|
||||||
:preview="false"
|
|
||||||
:muted="true"
|
|
||||||
:stream="localMediaStream"
|
|
||||||
/>
|
|
||||||
</q-card-section>
|
|
||||||
<div
|
|
||||||
class="absolute-bottom text-center bg-main-menu q-pa-xs"
|
|
||||||
>
|
|
||||||
{{ localParticipant.displayName }}
|
|
||||||
</div>
|
|
||||||
<!-- <q-card-section-->
|
|
||||||
<!-- class="bg-black text-subtitle2 text-center q-pb-sm q-pr-sm q-pl-sm q-pt-none"-->
|
|
||||||
<!-- >-->
|
|
||||||
<!-- {{ localParticipant.displayName }}-->
|
|
||||||
<!-- </q-card-section>-->
|
|
||||||
</q-card>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import CscMedia from '../../CscMedia'
|
|
||||||
export default {
|
|
||||||
name: 'CscConferenceLocalParticipant',
|
|
||||||
components: {
|
|
||||||
CscMedia
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
localParticipant: {
|
|
||||||
type: Object,
|
|
||||||
default: () => {
|
|
||||||
return {
|
|
||||||
displayName: ''
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
localMediaStream: {
|
|
||||||
type: MediaStream,
|
|
||||||
default: null
|
|
||||||
},
|
|
||||||
isMicrophoneEnabled: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
isCameraEnabled: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
isScreenEnabled: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
localMediaStream (stream) {
|
|
||||||
this.assignStream(stream)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mounted () {
|
|
||||||
this.assignStream(this.localMediaStream)
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
assignStream (stream) {
|
|
||||||
if (this.$refs.cscMedia) {
|
|
||||||
this.$refs.cscMedia.assignStream(stream)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
@ -1,93 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div
|
|
||||||
id="csc-conf-participants-cont"
|
|
||||||
class="row justify-right items-center"
|
|
||||||
>
|
|
||||||
<csc-conference-local-participant
|
|
||||||
ref="localParticipant"
|
|
||||||
:local-participant="localParticipant"
|
|
||||||
:local-media-stream="localMediaStream"
|
|
||||||
:is-microphone-enabled="isMicrophoneEnabled"
|
|
||||||
:is-camera-enabled="isCameraEnabled"
|
|
||||||
:is-screen-enabled="isScreenEnabled"
|
|
||||||
@click.native="setSelectedParticipant('local')"
|
|
||||||
/>
|
|
||||||
<div
|
|
||||||
id="csc-conf-remote-participants-cont"
|
|
||||||
>
|
|
||||||
<csc-conference-remote-participant
|
|
||||||
v-for="participantId in participantsList"
|
|
||||||
:key="participantId"
|
|
||||||
:remote-participant="remoteParticipant(participantId)"
|
|
||||||
:has-remote-video="hasRemoteVideo(participantId)"
|
|
||||||
:remote-media-stream="remoteMediaStream"
|
|
||||||
:remote-media-streams="remoteMediaStreams"
|
|
||||||
@click.native="setSelectedParticipant(participantId)"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import {
|
|
||||||
mapGetters,
|
|
||||||
mapState
|
|
||||||
} from 'vuex'
|
|
||||||
import CscConferenceRemoteParticipant from './CscConferenceRemoteParticipant'
|
|
||||||
import CscConferenceLocalParticipant from './CscConferenceLocalParticipant'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'CscConferenceParticipants',
|
|
||||||
components: {
|
|
||||||
CscConferenceRemoteParticipant,
|
|
||||||
CscConferenceLocalParticipant
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
...mapState('conference', [
|
|
||||||
'remoteMediaStreams'
|
|
||||||
]),
|
|
||||||
...mapGetters('conference', [
|
|
||||||
'participantsList',
|
|
||||||
'localParticipant',
|
|
||||||
'localMediaStream',
|
|
||||||
'isMicrophoneEnabled',
|
|
||||||
'isCameraEnabled',
|
|
||||||
'isScreenEnabled',
|
|
||||||
'remoteParticipant',
|
|
||||||
'remoteMediaStream',
|
|
||||||
'hasRemoteVideo'
|
|
||||||
])
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
localMediaStream (stream) {
|
|
||||||
this.assignLocalMediaStream(stream)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mounted () {
|
|
||||||
this.assignLocalMediaStream(this.localMediaStream)
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
assignLocalMediaStream (stream) {
|
|
||||||
if (this.$refs.localParticipant) {
|
|
||||||
this.$refs.localParticipant.assignStream(stream)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
setSelectedParticipant (participant) {
|
|
||||||
this.$store.commit('conference/setSelectedParticipant', participant)
|
|
||||||
this.$store.commit('conference/setManualSelection', true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="stylus" rel="stylesheet/stylus">
|
|
||||||
#csc-conf-participants-cont
|
|
||||||
padding 0px 20px 10px 20px
|
|
||||||
display list-item
|
|
||||||
height calc(100vh - 150px)
|
|
||||||
overflow hidden
|
|
||||||
@media (max-width: $breakpoint-sm)
|
|
||||||
font-size 73px
|
|
||||||
left -18px
|
|
||||||
top -2px
|
|
||||||
</style>
|
|
@ -1,172 +0,0 @@
|
|||||||
<template>
|
|
||||||
<q-card
|
|
||||||
class="bg-transparent"
|
|
||||||
flat
|
|
||||||
>
|
|
||||||
<q-card-section
|
|
||||||
class="relative-position bg-black text-center full-width no-padding"
|
|
||||||
style="height: 100px"
|
|
||||||
>
|
|
||||||
<q-icon
|
|
||||||
v-ripple
|
|
||||||
name="more_vert"
|
|
||||||
class="absolute-left"
|
|
||||||
style="z-index: 1; padding-top: 3px;"
|
|
||||||
>
|
|
||||||
<csc-popup-menu>
|
|
||||||
<csc-popup-menu-item
|
|
||||||
color="primary"
|
|
||||||
dense
|
|
||||||
:label="audioLabel()"
|
|
||||||
@click="toggleAudio()"
|
|
||||||
/>
|
|
||||||
</csc-popup-menu>
|
|
||||||
</q-icon>
|
|
||||||
<q-icon
|
|
||||||
v-show="isAudioMuted"
|
|
||||||
v-ripple
|
|
||||||
name="volume_off"
|
|
||||||
class="absolute-right"
|
|
||||||
:style="audioIconStyle"
|
|
||||||
/>
|
|
||||||
<q-icon
|
|
||||||
v-show="!isAudioMuted"
|
|
||||||
v-ripple
|
|
||||||
name="volume_up"
|
|
||||||
class="absolute-right"
|
|
||||||
:style="audioIconStyle"
|
|
||||||
/>
|
|
||||||
<q-avatar
|
|
||||||
v-show="!hasRemoteVideo"
|
|
||||||
class="absolute-center"
|
|
||||||
style="top: 40px"
|
|
||||||
>
|
|
||||||
<q-icon
|
|
||||||
name="person"
|
|
||||||
size="32px"
|
|
||||||
/>
|
|
||||||
</q-avatar>
|
|
||||||
<csc-media
|
|
||||||
v-show="hasRemoteVideo"
|
|
||||||
ref="cscMedia"
|
|
||||||
class="csc-media-cont"
|
|
||||||
:preview="false"
|
|
||||||
:muted="true"
|
|
||||||
/>
|
|
||||||
</q-card-section>
|
|
||||||
<div
|
|
||||||
class="absolute-bottom text-center bg-main-menu q-pa-xs"
|
|
||||||
>
|
|
||||||
{{ remoteParticipant.displayName }}
|
|
||||||
</div>
|
|
||||||
</q-card>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import _ from 'lodash'
|
|
||||||
import CscMedia from '../../CscMedia'
|
|
||||||
import CscPopupMenu from 'components/CscPopupMenu'
|
|
||||||
import CscPopupMenuItem from 'components/CscPopupMenuItem'
|
|
||||||
import {
|
|
||||||
TouchHold
|
|
||||||
} from 'quasar'
|
|
||||||
import {
|
|
||||||
mapGetters,
|
|
||||||
mapState
|
|
||||||
} from 'vuex'
|
|
||||||
export default {
|
|
||||||
name: 'CscConferenceRemoteParticipant',
|
|
||||||
directives: {
|
|
||||||
TouchHold
|
|
||||||
},
|
|
||||||
components: {
|
|
||||||
CscMedia,
|
|
||||||
CscPopupMenu,
|
|
||||||
CscPopupMenuItem
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
remoteParticipant: {
|
|
||||||
type: Object,
|
|
||||||
default: () => {
|
|
||||||
return {
|
|
||||||
displayName: ''
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
remoteMediaStream: {
|
|
||||||
type: Function,
|
|
||||||
default: null
|
|
||||||
},
|
|
||||||
remoteMediaStreams: {
|
|
||||||
type: Object,
|
|
||||||
default () {
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
},
|
|
||||||
hasRemoteVideo: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
data: function () {
|
|
||||||
return {
|
|
||||||
isAudioMuted: false,
|
|
||||||
localMediaStream: null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
...mapState('conference', [
|
|
||||||
'manualSelection'
|
|
||||||
]),
|
|
||||||
...mapGetters('conference', [
|
|
||||||
'selectedParticipant',
|
|
||||||
'mutedState'
|
|
||||||
]),
|
|
||||||
audioIconStyle () {
|
|
||||||
return 'z-index: 1; padding-top: 3px; padding-right: 3px;'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
remoteMediaStreams () {
|
|
||||||
this.assignStream()
|
|
||||||
},
|
|
||||||
mutedState () {
|
|
||||||
this.isAudioMuted = _.has(this.mutedState, this.remoteParticipant.id)
|
|
||||||
this.$refs.cscMedia.toggleAudio(this.isAudioMuted)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mounted () {
|
|
||||||
this.assignStream()
|
|
||||||
if (!this.manualSelection && this.remoteParticipant) {
|
|
||||||
this.$store.commit('conference/setSelectedParticipant', this.remoteParticipant.id)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
assignStream () {
|
|
||||||
if (this.$refs.cscMedia && _.has(this.remoteMediaStreams, this.remoteParticipant.id)) {
|
|
||||||
this.localMediaStream = this.remoteMediaStream(this.remoteParticipant.id)
|
|
||||||
this.$refs.cscMedia.assignStream(this.localMediaStream)
|
|
||||||
if (this.selectedParticipant === this.remoteParticipant.id) {
|
|
||||||
this.$store.commit('conference/setSelectedParticipant', 'local') // TODO improve (workaround to reset the mediaStream)
|
|
||||||
this.$store.commit('conference/setSelectedParticipant', this.remoteParticipant.id)
|
|
||||||
}
|
|
||||||
} else if (this.$refs.cscMedia) {
|
|
||||||
this.$refs.cscMedia.reset()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
toggleAudio () {
|
|
||||||
this.isAudioMuted
|
|
||||||
? this.$store.commit('conference/removeMutedState', this.remoteParticipant.id)
|
|
||||||
: this.$store.commit('conference/addMutedState', this.remoteParticipant.id)
|
|
||||||
},
|
|
||||||
audioLabel () {
|
|
||||||
return this.isAudioMuted
|
|
||||||
? this.$t('Unmute')
|
|
||||||
: this.$t('Mute')
|
|
||||||
},
|
|
||||||
showMenu () {
|
|
||||||
this.$refs.popover.open()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
@ -1,75 +0,0 @@
|
|||||||
<template>
|
|
||||||
<csc-dialog
|
|
||||||
ref="dialogComp"
|
|
||||||
:title="$t('Share conference')"
|
|
||||||
:title-icon="'link'"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
slot="content"
|
|
||||||
>
|
|
||||||
<q-input
|
|
||||||
ref="conferenceUrlInput"
|
|
||||||
:value="conferenceUrl"
|
|
||||||
readonly
|
|
||||||
@focus="selectConferenceUrl"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<q-btn
|
|
||||||
slot="actions"
|
|
||||||
color="primary"
|
|
||||||
flat
|
|
||||||
icon="link"
|
|
||||||
@click="copy"
|
|
||||||
>
|
|
||||||
{{ $t('Copy link') }}
|
|
||||||
</q-btn>
|
|
||||||
</csc-dialog>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import CscDialog from '../../CscDialog'
|
|
||||||
export default {
|
|
||||||
name: 'CscShareConferenceDialog',
|
|
||||||
components: {
|
|
||||||
CscDialog
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
conferenceUrl: {
|
|
||||||
type: String,
|
|
||||||
default: null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
data () {
|
|
||||||
return {
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {},
|
|
||||||
mounted () {
|
|
||||||
this.selectConferenceUrl()
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
open () {
|
|
||||||
this.$refs.dialogComp.open()
|
|
||||||
this.$nextTick(() => {
|
|
||||||
this.$refs.conferenceUrlInput.focus()
|
|
||||||
})
|
|
||||||
},
|
|
||||||
close () {
|
|
||||||
this.$refs.dialogComp.close()
|
|
||||||
},
|
|
||||||
copy () {
|
|
||||||
this.$refs.conferenceUrlInput.select()
|
|
||||||
document.execCommand('copy')
|
|
||||||
this.close()
|
|
||||||
},
|
|
||||||
selectConferenceUrl () {
|
|
||||||
if (this.$refs.conferenceUrlInput) {
|
|
||||||
this.$refs.conferenceUrlInput.select()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="stylus" rel="stylesheet/stylus">
|
|
||||||
</style>
|
|
@ -1,417 +0,0 @@
|
|||||||
<template>
|
|
||||||
<q-layout
|
|
||||||
id="csc-layout-conference"
|
|
||||||
view="lHh lpR lFf"
|
|
||||||
>
|
|
||||||
<q-header
|
|
||||||
id="csc-header-conference"
|
|
||||||
class="bg-transparent"
|
|
||||||
>
|
|
||||||
<q-toolbar
|
|
||||||
id="csc-header-toolbar-conference"
|
|
||||||
class="bg-transparent"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
v-if="isJoined"
|
|
||||||
class="q-mr-md text-h6"
|
|
||||||
>
|
|
||||||
<q-icon
|
|
||||||
name="meeting_room"
|
|
||||||
size="24px"
|
|
||||||
/>
|
|
||||||
{{ conferenceId }}
|
|
||||||
</div>
|
|
||||||
<q-space />
|
|
||||||
<div
|
|
||||||
v-if="isJoined"
|
|
||||||
class="q-mr-md text-h6"
|
|
||||||
>
|
|
||||||
<q-icon
|
|
||||||
name="person"
|
|
||||||
size="24px"
|
|
||||||
/>
|
|
||||||
{{ selectedParticipantName }}
|
|
||||||
</div>
|
|
||||||
<q-space />
|
|
||||||
<q-btn
|
|
||||||
color="tertiary"
|
|
||||||
icon="clear"
|
|
||||||
unelevated
|
|
||||||
dense
|
|
||||||
@click="close()"
|
|
||||||
/>
|
|
||||||
</q-toolbar>
|
|
||||||
</q-header>
|
|
||||||
<q-page-container
|
|
||||||
id="csc-page-conference"
|
|
||||||
>
|
|
||||||
<q-page
|
|
||||||
class="full-width row wrap justify-center items-start content-center"
|
|
||||||
>
|
|
||||||
<csc-conference-join
|
|
||||||
v-if="!isJoined"
|
|
||||||
class="bg-main-menu q-pa-lg"
|
|
||||||
style="z-index: 11"
|
|
||||||
:conference-id="conferenceId"
|
|
||||||
:has-conference-id="hasConferenceId"
|
|
||||||
:conference-url="conferenceUrl"
|
|
||||||
:local-media-stream="localMediaStream"
|
|
||||||
:is-microphone-enabled="isMicrophoneEnabled"
|
|
||||||
:is-camera-enabled="isCameraEnabled"
|
|
||||||
:is-screen-enabled="isScreenEnabled"
|
|
||||||
:is-media-enabled="isMediaEnabled"
|
|
||||||
:is-joining="isJoining"
|
|
||||||
:is-joined="isJoined"
|
|
||||||
:has-rtc-engine-capability-enabled="hasRtcEngineCapabilityEnabled"
|
|
||||||
@join="join"
|
|
||||||
/>
|
|
||||||
<csc-conference-joined
|
|
||||||
v-if="!isJoining && isJoined"
|
|
||||||
style="z-index: 10"
|
|
||||||
/>
|
|
||||||
<div
|
|
||||||
class="absolute-full"
|
|
||||||
>
|
|
||||||
<csc-media
|
|
||||||
v-show="showMainMedia"
|
|
||||||
ref="localMedia"
|
|
||||||
:muted="true"
|
|
||||||
:stream="localMediaStream"
|
|
||||||
:preview="false"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<csc-confirm-dialog
|
|
||||||
ref="confirmDialog"
|
|
||||||
title-icon="exit_to_app"
|
|
||||||
:title="$t('Leave conference')"
|
|
||||||
:message="$t('Leave current conference now!')"
|
|
||||||
@confirm="leave"
|
|
||||||
/>
|
|
||||||
</q-page>
|
|
||||||
</q-page-container>
|
|
||||||
<q-drawer
|
|
||||||
id="csc-conference-participants"
|
|
||||||
side="right"
|
|
||||||
:value="isJoined"
|
|
||||||
:width="150"
|
|
||||||
:mini-width="50"
|
|
||||||
>
|
|
||||||
<csc-conference-participants
|
|
||||||
ref="confParticipants"
|
|
||||||
class="no-margin q-mb-lg"
|
|
||||||
/>
|
|
||||||
</q-drawer>
|
|
||||||
<q-footer
|
|
||||||
id="csc-footer-conference"
|
|
||||||
class="bg-footer"
|
|
||||||
>
|
|
||||||
<q-toolbar>
|
|
||||||
<q-space />
|
|
||||||
<q-btn
|
|
||||||
:color="microphoneButtonColor"
|
|
||||||
class="text-dark q-mr-md"
|
|
||||||
style="margin-top: -60px"
|
|
||||||
icon="mic"
|
|
||||||
round
|
|
||||||
size="large"
|
|
||||||
:disable="!hasConferenceId || isJoining || !hasRtcEngineCapabilityEnabled"
|
|
||||||
@click="toggleMicrophone()"
|
|
||||||
/>
|
|
||||||
<q-btn
|
|
||||||
:color="cameraButtonColor"
|
|
||||||
class="text-dark q-mr-md"
|
|
||||||
style="margin-top: -60px"
|
|
||||||
icon="videocam"
|
|
||||||
round
|
|
||||||
size="large"
|
|
||||||
:disable="!hasConferenceId || isJoining || !hasRtcEngineCapabilityEnabled"
|
|
||||||
@click="toggleCamera()"
|
|
||||||
/>
|
|
||||||
<q-btn
|
|
||||||
:color="screenButtonColor"
|
|
||||||
class="text-dark q-mr-md"
|
|
||||||
style="margin-top: -60px"
|
|
||||||
icon="screen_share"
|
|
||||||
round
|
|
||||||
size="large"
|
|
||||||
:disable="!hasConferenceId || isJoining || !hasRtcEngineCapabilityEnabled"
|
|
||||||
@click="toggleScreen()"
|
|
||||||
/>
|
|
||||||
<q-btn
|
|
||||||
v-if="isJoined"
|
|
||||||
:color="screenButtonColor"
|
|
||||||
style="margin-top: -60px"
|
|
||||||
icon="more_vert"
|
|
||||||
round
|
|
||||||
size="large"
|
|
||||||
:disable="!hasConferenceId || isJoining || !hasRtcEngineCapabilityEnabled"
|
|
||||||
>
|
|
||||||
<q-menu
|
|
||||||
ref="popover"
|
|
||||||
:auto-close="true"
|
|
||||||
:disable="conferenceHasParticipants"
|
|
||||||
>
|
|
||||||
<q-list
|
|
||||||
link
|
|
||||||
class="no-border"
|
|
||||||
>
|
|
||||||
<q-item
|
|
||||||
class="cursor-pointer"
|
|
||||||
>
|
|
||||||
<q-item-section
|
|
||||||
@click="toggleMuteAll()"
|
|
||||||
>
|
|
||||||
<q-item-label>{{ muteLabel }}</q-item-label>
|
|
||||||
</q-item-section>
|
|
||||||
</q-item>
|
|
||||||
</q-list>
|
|
||||||
</q-menu>
|
|
||||||
</q-btn>
|
|
||||||
<q-space />
|
|
||||||
</q-toolbar>
|
|
||||||
</q-footer>
|
|
||||||
</q-layout>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import _ from 'lodash'
|
|
||||||
import {
|
|
||||||
mapGetters,
|
|
||||||
mapState,
|
|
||||||
mapActions
|
|
||||||
} from 'vuex'
|
|
||||||
import CscConferenceJoin from 'components/pages/Conference/CscConferenceJoin'
|
|
||||||
import CscConferenceJoined from 'components/pages/Conference/CscConferenceJoined'
|
|
||||||
import CscMedia from 'components/CscMedia'
|
|
||||||
import CscConfirmDialog from 'components/CscConfirmationDialog'
|
|
||||||
import CscConferenceParticipants from 'components/pages/Conference/CscConferenceParticipants'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'CscConferenceLayout',
|
|
||||||
components: {
|
|
||||||
CscConferenceParticipants,
|
|
||||||
CscConfirmDialog,
|
|
||||||
CscMedia,
|
|
||||||
CscConferenceJoin,
|
|
||||||
CscConferenceJoined
|
|
||||||
},
|
|
||||||
data: function () {
|
|
||||||
return {
|
|
||||||
selectedMediaStream: null,
|
|
||||||
selectedParticipantName: null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
...mapGetters('call', [
|
|
||||||
'hasRtcEngineCapabilityEnabled'
|
|
||||||
]),
|
|
||||||
...mapState('conference', [
|
|
||||||
'selectedParticipant'
|
|
||||||
]),
|
|
||||||
...mapGetters('conference', [
|
|
||||||
'conferenceId',
|
|
||||||
'conferenceUrl',
|
|
||||||
'hasConferenceId',
|
|
||||||
'isConferencingEnabled',
|
|
||||||
'isJoined',
|
|
||||||
'isJoining',
|
|
||||||
'isMicrophoneEnabled',
|
|
||||||
'isCameraEnabled',
|
|
||||||
'isScreenEnabled',
|
|
||||||
'isMediaEnabled',
|
|
||||||
'localParticipant',
|
|
||||||
'localMediaStream',
|
|
||||||
'participantsList',
|
|
||||||
'remoteParticipant',
|
|
||||||
'remoteMediaStream',
|
|
||||||
'remoteMediaStreams',
|
|
||||||
'hasRemoteVideo',
|
|
||||||
'mutedState'
|
|
||||||
]),
|
|
||||||
...mapGetters('user', [
|
|
||||||
'getUsername'
|
|
||||||
]),
|
|
||||||
microphoneButtonColor () {
|
|
||||||
if (this.isMicrophoneEnabled) {
|
|
||||||
return 'primary'
|
|
||||||
} else {
|
|
||||||
return 'grey'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
cameraButtonColor () {
|
|
||||||
if (this.isCameraEnabled) {
|
|
||||||
return 'primary'
|
|
||||||
} else {
|
|
||||||
return 'grey'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
screenButtonColor () {
|
|
||||||
if (this.isScreenEnabled) {
|
|
||||||
return 'primary'
|
|
||||||
} else {
|
|
||||||
return 'grey'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
selectedHasVideo () {
|
|
||||||
if (this.selectedParticipant === 'local') {
|
|
||||||
return this.isVideoEnabled
|
|
||||||
} else {
|
|
||||||
return this.hasRemoteVideo(this.selectedParticipant)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
showMainMedia () {
|
|
||||||
return (!this.isJoined && this.isVideoEnabled) || this.selectedHasVideo
|
|
||||||
},
|
|
||||||
isVideoEnabled () {
|
|
||||||
return this.isMediaEnabled && (this.isCameraEnabled || this.isScreenEnabled)
|
|
||||||
},
|
|
||||||
conferenceHasParticipants () {
|
|
||||||
return Object.keys(this.participantsList).length < 1
|
|
||||||
},
|
|
||||||
muteLabel () {
|
|
||||||
return _.isEmpty(this.mutedState)
|
|
||||||
? this.$t('Mute all')
|
|
||||||
: this.$t('Unmute all')
|
|
||||||
}
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
hasConferenceId (value) {
|
|
||||||
if (!value) {
|
|
||||||
this.$store.commit('conference/disposeLocalMedia')
|
|
||||||
}
|
|
||||||
},
|
|
||||||
selectedParticipant: {
|
|
||||||
handler: function (participant) {
|
|
||||||
if (participant) {
|
|
||||||
this.showSelectedParticipant(participant)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
deep: true
|
|
||||||
},
|
|
||||||
localMediaStream (stream) {
|
|
||||||
if (this.$refs.localMedia && (stream === null || stream === undefined)) {
|
|
||||||
this.$refs.localMedia.reset()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
...mapActions('conference', [
|
|
||||||
'leave'
|
|
||||||
]),
|
|
||||||
close () {
|
|
||||||
if (!this.isJoined) {
|
|
||||||
this.$router.push({ path: '/user/dashboard' })
|
|
||||||
this.$store.commit('conference/disposeLocalMedia')
|
|
||||||
} else {
|
|
||||||
this.$refs.confirmDialog.open()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
toggleMicrophone () {
|
|
||||||
if (this.hasConferenceId) {
|
|
||||||
this.$store.dispatch('conference/toggleMicrophone')
|
|
||||||
}
|
|
||||||
},
|
|
||||||
toggleCamera () {
|
|
||||||
if (this.hasConferenceId) {
|
|
||||||
this.$store.dispatch('conference/toggleCamera')
|
|
||||||
}
|
|
||||||
},
|
|
||||||
toggleScreen () {
|
|
||||||
if (this.hasConferenceId) {
|
|
||||||
this.$store.dispatch('conference/toggleScreen')
|
|
||||||
}
|
|
||||||
},
|
|
||||||
toggleMuteAll () {
|
|
||||||
if (_.isEmpty(this.mutedState)) {
|
|
||||||
this.$store.dispatch('conference/muteAll')
|
|
||||||
} else {
|
|
||||||
this.$store.dispatch('conference/unMuteAll')
|
|
||||||
}
|
|
||||||
},
|
|
||||||
async join (conferenceId) {
|
|
||||||
if (this.hasConferenceId) {
|
|
||||||
await this.$store.dispatch('conference/join', conferenceId)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
showSelectedParticipant (participant) {
|
|
||||||
if (this.$refs.localMedia) {
|
|
||||||
switch (participant) {
|
|
||||||
case 'local':
|
|
||||||
if (this.localParticipant) {
|
|
||||||
this.selectedParticipantName = this.localParticipant.displayName
|
|
||||||
this.selectedMediaStream = this.localMediaStream
|
|
||||||
this.$refs.localMedia.assignStream(this.selectedMediaStream)
|
|
||||||
}
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
this.selectedMediaStream = this.remoteMediaStream(participant)
|
|
||||||
this.$refs.localMedia.assignStream(this.selectedMediaStream)
|
|
||||||
this.selectedParticipantName = this.remoteParticipant(participant) ? this.remoteParticipant(participant).displayName : ''
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="stylus" rel="stylesheet/stylus">
|
|
||||||
#csc-conf-selected-participant-name
|
|
||||||
position absolute
|
|
||||||
top 20px
|
|
||||||
bottom 0
|
|
||||||
right 0
|
|
||||||
left 0
|
|
||||||
z-index 2
|
|
||||||
background-color $conf-participant-box-color
|
|
||||||
color $primary
|
|
||||||
font-size 20px
|
|
||||||
width 130px
|
|
||||||
height 45px
|
|
||||||
padding 10px
|
|
||||||
@media (max-width: $breakpoint-sm)
|
|
||||||
font-size 16px
|
|
||||||
width 100px
|
|
||||||
height 36px
|
|
||||||
padding 8px
|
|
||||||
#csc-conf-main-media
|
|
||||||
position absolute
|
|
||||||
top 0
|
|
||||||
bottom 0
|
|
||||||
right 0
|
|
||||||
left 0
|
|
||||||
z-index 1
|
|
||||||
background-color black
|
|
||||||
font-size 0
|
|
||||||
|
|
||||||
#csc-conf-header
|
|
||||||
z-index 2
|
|
||||||
top 0
|
|
||||||
left 0
|
|
||||||
right 0
|
|
||||||
position fixed
|
|
||||||
background-color transparent
|
|
||||||
height $call-footer-height
|
|
||||||
.csc-conf-button.q-btn
|
|
||||||
.q-btn-inner
|
|
||||||
color white
|
|
||||||
#csc-conf-body
|
|
||||||
position relative
|
|
||||||
z-index 2
|
|
||||||
top $call-footer-height
|
|
||||||
#csc-conf-footer
|
|
||||||
z-index 2
|
|
||||||
bottom 0
|
|
||||||
left 0
|
|
||||||
right 0
|
|
||||||
position fixed
|
|
||||||
background-color $layout-aside-background
|
|
||||||
height $call-footer-height
|
|
||||||
|
|
||||||
#csc-conf-actions
|
|
||||||
margin: -28px
|
|
||||||
.q-btn:last-child
|
|
||||||
margin-right 0
|
|
||||||
.q-btn
|
|
||||||
margin-right $flex-gutter-sm
|
|
||||||
</style>
|
|
@ -1,54 +0,0 @@
|
|||||||
import loadScript from 'load-script'
|
|
||||||
|
|
||||||
const RTC_ENGINE_LIBRARY_ID = 'ngcp-rtc-engine-library'
|
|
||||||
|
|
||||||
export const LocalMedia = {
|
|
||||||
audioOnly: 'audioOnly',
|
|
||||||
audioVideo: 'audioVideo',
|
|
||||||
videoOnly: 'videoOnly',
|
|
||||||
audioScreen: 'audioScreen',
|
|
||||||
screenOnly: 'screenOnly'
|
|
||||||
}
|
|
||||||
|
|
||||||
export function loadRtcEngineLibrary ({ scriptUrl }) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const script = document.getElementById(RTC_ENGINE_LIBRARY_ID)
|
|
||||||
if (!script) {
|
|
||||||
loadScript(scriptUrl, {
|
|
||||||
attrs: {
|
|
||||||
id: RTC_ENGINE_LIBRARY_ID
|
|
||||||
}
|
|
||||||
}, (err) => {
|
|
||||||
if (err) {
|
|
||||||
reject(new Error('Unable to load RTC:Engine client library'))
|
|
||||||
} else {
|
|
||||||
resolve()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
resolve()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export function unloadRtcEngineLibrary () {
|
|
||||||
const script = document.getElementById(RTC_ENGINE_LIBRARY_ID)
|
|
||||||
if (script) {
|
|
||||||
script.remove()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function rtcEngineCreateMedia (localMedia) {
|
|
||||||
// eslint-disable-next-line no-undef
|
|
||||||
const localMediaBuilder = cdk.media.create()
|
|
||||||
if (localMedia === LocalMedia.audioOnly || localMedia === LocalMedia.audioVideo ||
|
|
||||||
localMedia === LocalMedia.audioScreen) {
|
|
||||||
localMediaBuilder.enableMicrophone()
|
|
||||||
}
|
|
||||||
if (localMedia === LocalMedia.audioVideo || localMedia === LocalMedia.videoOnly) {
|
|
||||||
localMediaBuilder.enableCamera()
|
|
||||||
} else if (localMedia === LocalMedia.audioScreen || localMedia === LocalMedia.screenOnly) {
|
|
||||||
localMediaBuilder.enableScreen()
|
|
||||||
}
|
|
||||||
return await localMediaBuilder.build()
|
|
||||||
}
|
|
@ -1,432 +0,0 @@
|
|||||||
import Vue from 'vue'
|
|
||||||
import {
|
|
||||||
RequestState
|
|
||||||
} from './common'
|
|
||||||
|
|
||||||
const MediaTypes = {
|
|
||||||
mic: 'mic',
|
|
||||||
micCam: 'micCam',
|
|
||||||
cam: 'cam',
|
|
||||||
micScreen: 'micScreen',
|
|
||||||
screen: 'screen'
|
|
||||||
}
|
|
||||||
|
|
||||||
export default {
|
|
||||||
namespaced: true,
|
|
||||||
state: {
|
|
||||||
conferencingEnabled: false,
|
|
||||||
microphoneEnabled: false,
|
|
||||||
cameraEnabled: false,
|
|
||||||
screenEnabled: false,
|
|
||||||
localMediaState: RequestState.initiated,
|
|
||||||
localMediaError: null,
|
|
||||||
joinState: RequestState.initiated,
|
|
||||||
joinError: null,
|
|
||||||
leaveState: RequestState.initiated,
|
|
||||||
leaveError: null,
|
|
||||||
participants: [],
|
|
||||||
mutedState: {},
|
|
||||||
remoteMediaStreams: {},
|
|
||||||
selectedParticipant: null,
|
|
||||||
manualSelection: false
|
|
||||||
},
|
|
||||||
getters: {
|
|
||||||
username (state, getters, rootState, rootGetters) {
|
|
||||||
return rootGetters['user/getUsername']
|
|
||||||
},
|
|
||||||
conferenceId (state, getters, rootState, rootGetters) {
|
|
||||||
return rootGetters.conferenceId
|
|
||||||
},
|
|
||||||
conferenceUrl (state, getters, rootState, rootGetters) {
|
|
||||||
return rootGetters.conferenceUrl
|
|
||||||
},
|
|
||||||
hasConferenceId (state, getters, rootState, rootGetters) {
|
|
||||||
return rootGetters.hasConferenceId
|
|
||||||
},
|
|
||||||
isJoined (state) {
|
|
||||||
return state.joinState === RequestState.succeeded
|
|
||||||
},
|
|
||||||
isJoining (state) {
|
|
||||||
return state.joinState === RequestState.requesting
|
|
||||||
},
|
|
||||||
isLeft (state) {
|
|
||||||
return state.leaveState === RequestState.succeeded
|
|
||||||
},
|
|
||||||
isLeaving (state) {
|
|
||||||
return state.leaveState === RequestState.requesting
|
|
||||||
},
|
|
||||||
isConferencingEnabled (state) {
|
|
||||||
return state.conferencingEnabled
|
|
||||||
},
|
|
||||||
isMicrophoneEnabled (state) {
|
|
||||||
return state.microphoneEnabled
|
|
||||||
},
|
|
||||||
isCameraEnabled (state) {
|
|
||||||
return state.cameraEnabled
|
|
||||||
},
|
|
||||||
isScreenEnabled (state) {
|
|
||||||
return state.screenEnabled
|
|
||||||
},
|
|
||||||
isMediaEnabled (state) {
|
|
||||||
return (state.localMediaState === RequestState.succeeded ||
|
|
||||||
state.localMediaState === RequestState.requesting) && Vue.$conference.hasLocalMediaStream()
|
|
||||||
},
|
|
||||||
localMediaStream (state) {
|
|
||||||
if ((state.localMediaState === RequestState.succeeded ||
|
|
||||||
state.localMediaState === RequestState.requesting) && Vue.$conference.hasLocalMediaStream()) {
|
|
||||||
return Vue.$conference.getLocalMediaStreamNative()
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
},
|
|
||||||
hasLocalMediaStream (state) {
|
|
||||||
return (state.localMediaState === RequestState.succeeded ||
|
|
||||||
state.localMediaState === RequestState.requesting) && Vue.$conference.hasLocalMediaStream()
|
|
||||||
},
|
|
||||||
localParticipant (state) {
|
|
||||||
if (state.joinState === RequestState.succeeded) {
|
|
||||||
return Vue.$conference.getLocalParticipant()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
remoteParticipant: () => (participantId) => {
|
|
||||||
return Vue.$conference.getRemoteParticipant(participantId)
|
|
||||||
},
|
|
||||||
remoteMediaStream: () => (participantId) => {
|
|
||||||
const participant = Vue.$conference.getRemoteParticipant(participantId)
|
|
||||||
if (participant) {
|
|
||||||
return participant.mediaStream ? participant.mediaStream.getStream() : null
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
},
|
|
||||||
participantsList (state) {
|
|
||||||
return state.participants
|
|
||||||
},
|
|
||||||
mutedState (state) {
|
|
||||||
return state.mutedState
|
|
||||||
},
|
|
||||||
remoteMediaStreams (state) {
|
|
||||||
return state.remoteMediaStreams
|
|
||||||
},
|
|
||||||
hasRemoteVideo: () => (participantId) => {
|
|
||||||
const participant = Vue.$conference.getRemoteParticipant(participantId)
|
|
||||||
if (participant) {
|
|
||||||
return participant.mediaStream ? participant.mediaStream.hasVideo() : false
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
},
|
|
||||||
selectedParticipant (state) {
|
|
||||||
return state.selectedParticipant
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mutations: {
|
|
||||||
enableConferencing (state) {
|
|
||||||
state.conferencingEnabled = true
|
|
||||||
},
|
|
||||||
disableConferencing (state) {
|
|
||||||
state.conferencingEnabled = false
|
|
||||||
},
|
|
||||||
enableMicrophone (state) {
|
|
||||||
state.microphoneEnabled = true
|
|
||||||
},
|
|
||||||
disableMicrophone (state) {
|
|
||||||
state.microphoneEnabled = false
|
|
||||||
},
|
|
||||||
enableCamera (state) {
|
|
||||||
state.cameraEnabled = true
|
|
||||||
},
|
|
||||||
disableCamera (state) {
|
|
||||||
state.cameraEnabled = false
|
|
||||||
},
|
|
||||||
enableScreen (state) {
|
|
||||||
state.screenEnabled = true
|
|
||||||
},
|
|
||||||
disableScreen (state) {
|
|
||||||
state.screenEnabled = false
|
|
||||||
},
|
|
||||||
localMediaRequesting (state) {
|
|
||||||
state.localMediaState = RequestState.requesting
|
|
||||||
state.localMediaError = null
|
|
||||||
},
|
|
||||||
localMediaSucceeded (state) {
|
|
||||||
state.localMediaState = RequestState.succeeded
|
|
||||||
state.localMediaError = null
|
|
||||||
},
|
|
||||||
localMediaFailed (state, error) {
|
|
||||||
state.localMediaState = RequestState.failed
|
|
||||||
state.localMediaError = error
|
|
||||||
},
|
|
||||||
isLocalMediaRequesting (state) {
|
|
||||||
return state.localMediaState === RequestState.requesting
|
|
||||||
},
|
|
||||||
disposeLocalMedia (state) {
|
|
||||||
Vue.$conference.removeLocalMediaStream()
|
|
||||||
state.cameraEnabled = false
|
|
||||||
state.microphoneEnabled = false
|
|
||||||
state.screenEnabled = false
|
|
||||||
},
|
|
||||||
addRemoteMedia (state, participantId) {
|
|
||||||
Vue.set(state.remoteMediaStreams, participantId, participantId)
|
|
||||||
},
|
|
||||||
removeRemoteMedia (state, participantId) {
|
|
||||||
Vue.delete(state.remoteMediaStreams, participantId)
|
|
||||||
},
|
|
||||||
joinRequesting (state) {
|
|
||||||
state.joinState = RequestState.requesting
|
|
||||||
state.joinError = null
|
|
||||||
},
|
|
||||||
joinSucceeded (state) {
|
|
||||||
state.joinState = RequestState.succeeded
|
|
||||||
state.joinError = null
|
|
||||||
state.leaveState = null
|
|
||||||
state.selectedParticipant = 'local'
|
|
||||||
},
|
|
||||||
joinFailed (state, error) {
|
|
||||||
state.joinState = RequestState.failed
|
|
||||||
state.joinError = error
|
|
||||||
},
|
|
||||||
leaveRequesting (state) {
|
|
||||||
state.leaveState = RequestState.requesting
|
|
||||||
state.leaveError = null
|
|
||||||
state.joinState = null
|
|
||||||
},
|
|
||||||
leaveSucceeded (state) {
|
|
||||||
state.leaveState = RequestState.succeeded
|
|
||||||
state.leaveError = null
|
|
||||||
state.joinState = RequestState.initiated
|
|
||||||
state.joinError = null
|
|
||||||
state.selectedParticipant = null
|
|
||||||
state.remoteMediaStreams = {}
|
|
||||||
state.manualSelection = false
|
|
||||||
state.participants = []
|
|
||||||
state.mutedState = {}
|
|
||||||
},
|
|
||||||
leaveFailed (state, error) {
|
|
||||||
state.leaveState = RequestState.failed
|
|
||||||
state.leaveError = error
|
|
||||||
},
|
|
||||||
participantJoined (state, participant) {
|
|
||||||
if (state.participants.includes(participant.getId())) {
|
|
||||||
state.participants = state.participants.filter(($participant) => {
|
|
||||||
return participant.getId() !== $participant
|
|
||||||
})
|
|
||||||
}
|
|
||||||
state.participants.push(participant.getId())
|
|
||||||
},
|
|
||||||
participantLeft (state, participant) {
|
|
||||||
state.participants = state.participants.filter(($participant) => {
|
|
||||||
return participant.getId() !== $participant
|
|
||||||
})
|
|
||||||
},
|
|
||||||
setSelectedParticipant (state, participant) {
|
|
||||||
if (state.selectedParticipant === 'local' && !state.joinState === RequestState.succeeded) {
|
|
||||||
state.selectedParticipant = null
|
|
||||||
} else if (state.selectedParticipant === participant && !state.participants.includes(participant)) {
|
|
||||||
state.selectedParticipant = 'local'
|
|
||||||
state.manualSelection = false
|
|
||||||
} else {
|
|
||||||
state.selectedParticipant = participant
|
|
||||||
}
|
|
||||||
},
|
|
||||||
setManualSelection (state, val) {
|
|
||||||
state.manualSelection = val
|
|
||||||
},
|
|
||||||
addMutedState (state, participantId) {
|
|
||||||
Vue.set(state.mutedState, participantId, participantId)
|
|
||||||
},
|
|
||||||
removeMutedState (state, participantId) {
|
|
||||||
Vue.delete(state.mutedState, participantId)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
actions: {
|
|
||||||
createLocalMedia (context, type) {
|
|
||||||
const media = Vue.$rtcEngine.createMedia()
|
|
||||||
context.commit('localMediaRequesting')
|
|
||||||
switch (type) {
|
|
||||||
default:
|
|
||||||
case MediaTypes.mic:
|
|
||||||
media.enableMicrophone()
|
|
||||||
break
|
|
||||||
case MediaTypes.micCam:
|
|
||||||
media.enableMicrophone()
|
|
||||||
media.enableCamera()
|
|
||||||
break
|
|
||||||
case MediaTypes.micScreen:
|
|
||||||
media.enableMicrophone()
|
|
||||||
media.enableScreen()
|
|
||||||
break
|
|
||||||
case MediaTypes.cam:
|
|
||||||
media.enableCamera()
|
|
||||||
break
|
|
||||||
case MediaTypes.screen:
|
|
||||||
media.enableScreen()
|
|
||||||
break
|
|
||||||
}
|
|
||||||
let localMediaStream
|
|
||||||
return media.build().then(($localMediaStream) => {
|
|
||||||
localMediaStream = $localMediaStream
|
|
||||||
Vue.$conference.setLocalMediaStream(localMediaStream)
|
|
||||||
switch (type) {
|
|
||||||
default:
|
|
||||||
case MediaTypes.mic:
|
|
||||||
context.commit('enableMicrophone')
|
|
||||||
context.commit('disableCamera')
|
|
||||||
context.commit('disableScreen')
|
|
||||||
break
|
|
||||||
case MediaTypes.micCam:
|
|
||||||
context.commit('enableMicrophone')
|
|
||||||
context.commit('enableCamera')
|
|
||||||
context.commit('disableScreen')
|
|
||||||
break
|
|
||||||
case MediaTypes.micScreen:
|
|
||||||
context.commit('enableMicrophone')
|
|
||||||
context.commit('disableCamera')
|
|
||||||
context.commit('enableScreen')
|
|
||||||
break
|
|
||||||
case MediaTypes.cam:
|
|
||||||
context.commit('disableMicrophone')
|
|
||||||
context.commit('enableCamera')
|
|
||||||
context.commit('disableScreen')
|
|
||||||
break
|
|
||||||
case MediaTypes.screen:
|
|
||||||
context.commit('disableMicrophone')
|
|
||||||
context.commit('disableCamera')
|
|
||||||
context.commit('enableScreen')
|
|
||||||
break
|
|
||||||
}
|
|
||||||
return Promise.resolve()
|
|
||||||
}).then(() => {
|
|
||||||
if (context.getters.isJoined) {
|
|
||||||
return Vue.$conference.changeConferenceMedia()
|
|
||||||
} else {
|
|
||||||
return Promise.resolve()
|
|
||||||
}
|
|
||||||
}).then(() => {
|
|
||||||
context.commit('localMediaSucceeded', localMediaStream)
|
|
||||||
}).catch((err) => {
|
|
||||||
if (!context.getters.hasLocalMediaStream) {
|
|
||||||
context.commit('localMediaFailed', err.message)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
async enableMicrophone (context) {
|
|
||||||
if (!context.getters.isLocalMediaRequesting) {
|
|
||||||
let mediaType = MediaTypes.mic
|
|
||||||
if (context.getters.isCameraEnabled) {
|
|
||||||
mediaType = MediaTypes.micCam
|
|
||||||
} else if (context.getters.isScreenEnabled) {
|
|
||||||
mediaType = MediaTypes.micScreen
|
|
||||||
}
|
|
||||||
await context.dispatch('createLocalMedia', mediaType)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
disableMicrophone (context) {
|
|
||||||
if (!context.getters.isLocalMediaRequesting) {
|
|
||||||
let mediaType = null
|
|
||||||
if (context.getters.isCameraEnabled) {
|
|
||||||
mediaType = MediaTypes.cam
|
|
||||||
} else if (context.getters.isScreenEnabled) {
|
|
||||||
mediaType = MediaTypes.screen
|
|
||||||
}
|
|
||||||
if (mediaType === null) {
|
|
||||||
context.commit('disposeLocalMedia')
|
|
||||||
} else {
|
|
||||||
context.dispatch('createLocalMedia', mediaType)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
toggleMicrophone (context) {
|
|
||||||
if (!context.getters.isMicrophoneEnabled) {
|
|
||||||
context.dispatch('enableMicrophone')
|
|
||||||
} else {
|
|
||||||
context.dispatch('disableMicrophone')
|
|
||||||
}
|
|
||||||
},
|
|
||||||
enableCamera (context) {
|
|
||||||
if (!context.getters.isLocalMediaRequesting) {
|
|
||||||
context.dispatch('createLocalMedia', MediaTypes.micCam)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
disableCamera (context) {
|
|
||||||
if (!context.getters.isLocalMediaRequesting) {
|
|
||||||
let mediaType = null
|
|
||||||
if (context.getters.isMicrophoneEnabled) {
|
|
||||||
mediaType = MediaTypes.mic
|
|
||||||
}
|
|
||||||
if (mediaType === null) {
|
|
||||||
context.commit('disposeLocalMedia')
|
|
||||||
} else {
|
|
||||||
context.dispatch('createLocalMedia', mediaType)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
toggleCamera (context) {
|
|
||||||
if (!context.getters.isCameraEnabled) {
|
|
||||||
context.dispatch('enableCamera')
|
|
||||||
} else {
|
|
||||||
context.dispatch('disableCamera')
|
|
||||||
}
|
|
||||||
},
|
|
||||||
enableScreen (context) {
|
|
||||||
if (!context.getters.isLocalMediaRequesting) {
|
|
||||||
context.dispatch('createLocalMedia', MediaTypes.micScreen)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
disableScreen (context) {
|
|
||||||
if (!context.getters.isLocalMediaRequesting) {
|
|
||||||
let mediaType = null
|
|
||||||
if (context.getters.isMicrophoneEnabled) {
|
|
||||||
mediaType = MediaTypes.mic
|
|
||||||
}
|
|
||||||
if (mediaType === null) {
|
|
||||||
context.commit('disposeLocalMedia')
|
|
||||||
} else {
|
|
||||||
context.dispatch('createLocalMedia', mediaType)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
toggleScreen (context) {
|
|
||||||
if (!context.getters.isScreenEnabled) {
|
|
||||||
context.dispatch('enableScreen')
|
|
||||||
} else {
|
|
||||||
context.dispatch('disableScreen')
|
|
||||||
}
|
|
||||||
},
|
|
||||||
async join (context, conferenceId) {
|
|
||||||
try {
|
|
||||||
if (!Vue.$conference.hasLocalMediaStream()) {
|
|
||||||
await context.dispatch('enableMicrophone')
|
|
||||||
}
|
|
||||||
context.commit('joinRequesting')
|
|
||||||
await Vue.$conference.joinConference({
|
|
||||||
conferenceName: conferenceId,
|
|
||||||
displayName: context.getters.username
|
|
||||||
})
|
|
||||||
context.commit('joinSucceeded')
|
|
||||||
} catch (err) {
|
|
||||||
context.commit('joinFailed', err.message)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
async leave (context) {
|
|
||||||
if (context.getters.isJoined) {
|
|
||||||
try {
|
|
||||||
context.commit('leaveRequesting')
|
|
||||||
await Vue.$conference.leaveConference()
|
|
||||||
context.commit('leaveSucceeded')
|
|
||||||
} catch (err) {
|
|
||||||
context.commit('leaveFailed', err.message)
|
|
||||||
} finally {
|
|
||||||
context.commit('disposeLocalMedia')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
muteAll (context) {
|
|
||||||
for (const participant of context.getters.participantsList) {
|
|
||||||
context.commit('addMutedState', participant)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
unMuteAll (context) {
|
|
||||||
for (const participant of context.getters.participantsList) {
|
|
||||||
context.commit('removeMutedState', participant)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in new issue