TT#47708 Conferencing > show participant local video

Change-Id: I1ab7e1261673c27099f4f78cf6c8b5caf4531591
changes/63/34663/2
Carlo Venusino 6 years ago
parent b9bb89d765
commit 37909a6bcc

@ -39,6 +39,9 @@
<csc-conference-joined <csc-conference-joined
v-if="!isJoining && isJoined" v-if="!isJoining && isJoined"
/> />
<csc-conference-participants
v-if="!isJoining && isJoined"
/>
</div> </div>
<div <div
id="csc-conf-main-media" id="csc-conf-main-media"
@ -100,6 +103,7 @@
} from 'vuex' } from 'vuex'
import CscConferenceJoin from '../pages/Conference/CscConferenceJoin' import CscConferenceJoin from '../pages/Conference/CscConferenceJoin'
import CscConferenceJoined from '../pages/Conference/CscConferenceJoined' import CscConferenceJoined from '../pages/Conference/CscConferenceJoined'
import CscConferenceParticipants from '../pages/Conference/CscConferenceParticipants'
import CscMedia from "../CscMedia"; import CscMedia from "../CscMedia";
import CscSpinner from "../CscSpinner"; import CscSpinner from "../CscSpinner";
import { import {
@ -120,6 +124,7 @@
CscMedia, CscMedia,
CscConferenceJoin, CscConferenceJoin,
CscConferenceJoined, CscConferenceJoined,
CscConferenceParticipants,
QLayout, QLayout,
QBtn QBtn
}, },
@ -135,7 +140,11 @@
'isCameraEnabled', 'isCameraEnabled',
'isScreenEnabled', 'isScreenEnabled',
'isMediaEnabled', 'isMediaEnabled',
'localMediaStream' 'localMediaStream',
'participantsList',
'remoteMediaStream',
'remoteMediaStreams',
'hasRemoteMediaStream'
]), ]),
microphoneButtonColor() { microphoneButtonColor() {
if(this.isMicrophoneEnabled) { if(this.isMicrophoneEnabled) {

@ -2,7 +2,6 @@
<div <div
class="row justify-center items-center csc-conf-full-height" class="row justify-center items-center csc-conf-full-height"
> >
<div <div
id="csc-conf-join-content" id="csc-conf-join-content"
:class="contentClasses" :class="contentClasses"

@ -0,0 +1,66 @@
<template>
<q-card
class="csc-conf-participant-cont"
>
<q-card-media
class="csc-avatar-cont"
v-if="!localMediaStream || localMediaStream && (!isCameraEnabled && !isScreenEnabled)"
>
<img src="/statics/avatar.png">
</q-card-media>
<csc-media
ref="cscMedia"
v-show="localMediaStream && (isCameraEnabled || isScreenEnabled)"
class="csc-media-cont"
:muted="true"
:stream="localMediaStream"
:preview="true"
/>
<q-card-title
class="csc-conf-participants-item-title"
>
{{ localParticipant.displayName }}
</q-card-title>
</q-card>
</template>
<script>
import { QCard, QCardMedia, QCardTitle } from 'quasar-framework'
// import { mapGetters } from 'vuex'
import CscMedia from "../../CscMedia";
export default {
name: 'csc-conference-local-participant',
components: {
QCard,
QCardMedia,
QCardTitle,
CscMedia
},
props: [
'localParticipant',
'localMediaStream',
'isMicrophoneEnabled',
'isCameraEnabled',
'isScreenEnabled'
],
mounted(){
this.assignStream(this.localMediaStream);
},
methods: {
assignStream(stream) {
if(this.$refs.cscMedia) {
this.$refs.cscMedia.assignStream(stream);
}
}
},
watch: {
localMediaStream(stream) {
this.assignStream(stream);
}
}
}
</script>
<style lang="stylus" rel="stylesheet/stylus">
@import '../../../themes/app.common.styl'
</style>

@ -0,0 +1,80 @@
<template>
<div
class="row justify-right items-center"
id="csc-conf-participants-cont"
>
<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"
/>
<div
id="csc-conf-remote-participants-cont"
v-for="participantId in participantsList" :key="participantId">
<csc-conference-remote-participant
:participant-id="participantId"
/>
</div>
</div>
</template>
<script>
import {QCard, QCardMedia, QCardTitle} from 'quasar-framework'
import {mapGetters} from 'vuex'
import CscMedia from "../../CscMedia";
import CscConferenceRemoteParticipant from './CscConferenceRemoteParticipant'
import CscConferenceLocalParticipant from './CscConferenceLocalParticipant'
export default {
name: 'csc-conference-participants',
components: {
QCard,
QCardMedia,
QCardTitle,
CscMedia,
CscConferenceRemoteParticipant,
CscConferenceLocalParticipant
},
computed: {
...mapGetters('conference', [
'participantsList',
'localParticipant',
'localMediaStream',
'isMicrophoneEnabled',
'isCameraEnabled',
'isScreenEnabled'
])
},
mounted() {
this.assignLocalMediaStream(this.localMediaStream);
},
methods: {
assignLocalMediaStream(stream) {
if(this.$refs.localParticipant) {
this.$refs.localParticipant.assignStream(stream);
}
}
},
watch: {
localMediaStream(stream) {
this.assignLocalMediaStream(stream);
}
}
}
</script>
<style lang="stylus" rel="stylesheet/stylus">
@import '../../../themes/app.common.styl'
#csc-conf-participants-cont
float right
padding 10px
display inline-block
height calc(100vh - 150px)
overflow hidden
#csc-conf-remote-participants-cont
overflow scroll
</style>

@ -0,0 +1,58 @@
<template>
<q-card
class="csc-conf-participant-cont"
>
<q-card-media
class="csc-avatar-cont"
v-show="!hasRemoteMediaStream(participantId)"
>
<img src="/statics/avatar.png">
</q-card-media>
<csc-media
v-show="hasRemoteMediaStream(participantId)"
class="csc-media-cont"
ref="{{participantId}}"
:muted="false"
:stream="remoteMediaStream(participantId)"
:preview="true"
/>
<q-card-title
class="csc-conf-participants-item-title"
>
{{remoteParticipant(participantId).displayName}}
</q-card-title>
</q-card>
</template>
<script>
import { QCard, QCardMedia, QCardTitle } from 'quasar-framework'
import { mapGetters } from 'vuex'
import CscMedia from "../../CscMedia";
export default {
name: 'csc-conference-remote-participant',
components: {
QCard,
QCardMedia,
QCardTitle,
CscMedia
},
props:['participantId'],
computed: {
...mapGetters('conference', [
'remoteParticipant',
'remoteMediaStream',
'hasRemoteMediaStream'
])
},
mounted(){
// workaround to retrigger :stream binding on csc-media component
if(this.hasRemoteMediaStream(this.participantId)){
this.$store.commit('conference/addRemoteMedia', this.participantId);
}
}
}
</script>
<style lang="stylus" rel="stylesheet/stylus">
@import '../../../themes/app.common.styl'
</style>

@ -47,6 +47,7 @@ export class ConferencePlugin {
return new Promise((resolve, reject)=>{ return new Promise((resolve, reject)=>{
options.localMediaStream = this.getLocalMediaStream(); options.localMediaStream = this.getLocalMediaStream();
this.getNetwork().joinConference(options).then((conference)=>{ this.getNetwork().joinConference(options).then((conference)=>{
this.conference = conference;
resolve(conference); resolve(conference);
}).catch((err)=>{ }).catch((err)=>{
reject(err); reject(err);
@ -146,12 +147,13 @@ export class ConferencePlugin {
} }
getLocalParticipant() { getLocalParticipant() {
this.conference.getLocalParticipant(); return this.conference.getLocalParticipant();
} }
getRemoteParticipant(id) { getRemoteParticipant(id) {
this.conference.getRemoteParticipant(id); return this.conference.getRemoteParticipant(id);
} }
} }
export default { export default {

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

@ -25,7 +25,8 @@ export default {
joinError: null, joinError: null,
leaveState: RequestState.initiated, leaveState: RequestState.initiated,
leaveError: null, leaveError: null,
participants: [] participants: [],
remoteMediaStreams: []
}, },
getters: { getters: {
username(state, getters, rootState, rootGetters) { username(state, getters, rootState, rootGetters) {
@ -78,7 +79,33 @@ export default {
hasLocalMediaStream(state) { hasLocalMediaStream(state) {
return (state.localMediaState === RequestState.succeeded || return (state.localMediaState === RequestState.succeeded ||
state.localMediaState === RequestState.requesting) && Vue.$conference.hasLocalMediaStream(); 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: (state) => (participantId) => {
if(state.remoteMediaStreams.includes(participantId)){
const participant = Vue.$conference.getRemoteParticipant(participantId);
return participant.mediaStream ? participant.mediaStream.getStream() : null;
}
return null;
},
participantsList(state) {
return state.participants;
},
remoteMediaStreams(state) {
return state.remoteMediaStreams;
},
hasRemoteMediaStream: (state) => (participantId) => {
return state.remoteMediaStreams.includes(participantId)
} }
}, },
mutations: { mutations: {
enableConferencing(state) { enableConferencing(state) {
@ -126,6 +153,20 @@ export default {
state.microphoneEnabled = false; state.microphoneEnabled = false;
state.screenEnabled = false; state.screenEnabled = false;
}, },
addRemoteMedia(state, participantId) {
if(state.remoteMediaStreams.includes(participantId)){
state.remoteMediaStreams = state.remoteMediaStreams.filter(($participant)=>{
return participantId !== $participant;
});
}
state.remoteMediaStreams.push(participantId);
},
removeRemoteMedia(state, participant) {
state.remoteMediaStreams = state.remoteMediaStreams.filter(($participant)=>{
return participant !== $participant;
});
},
joinRequesting(state) { joinRequesting(state) {
state.joinState = RequestState.requesting; state.joinState = RequestState.requesting;
state.joinError = null; state.joinError = null;
@ -133,6 +174,7 @@ export default {
joinSucceeded(state) { joinSucceeded(state) {
state.joinState = RequestState.succeeded; state.joinState = RequestState.succeeded;
state.joinError = null; state.joinError = null;
state.leaveState = null;
}, },
joinFailed(state, error) { joinFailed(state, error) {
state.joinState = RequestState.failed; state.joinState = RequestState.failed;
@ -141,6 +183,7 @@ export default {
leaveRequesting(state) { leaveRequesting(state) {
state.leaveState = RequestState.requesting; state.leaveState = RequestState.requesting;
state.leaveError = null; state.leaveError = null;
state.joinState = null;
}, },
leaveSucceeded(state) { leaveSucceeded(state) {
state.leaveState = RequestState.succeeded; state.leaveState = RequestState.succeeded;
@ -153,12 +196,16 @@ export default {
state.leaveError = error; state.leaveError = error;
}, },
participantJoined(state, participant) { participantJoined(state, participant) {
state.participants.push(participant.getId()); if(state.participants.includes(participant.getId())){
state.participants = state.participants.filter(($participant)=>{
return participant.getId() !== $participant;
});
}
state.participants.push(participant.getId())
}, },
participantLeft(state, participant) { participantLeft(state, participant) {
state.participants = state.participants.filter(($participant)=>{ state.participants = state.participants.filter(($participant)=>{
return participant.getId() !== $participant.getId(); return participant.getId() !== $participant;
}); });
} }
}, },

@ -121,6 +121,19 @@ export const store = new Vuex.Store({
store.commit('conference/leftSuccessfully', conference); store.commit('conference/leftSuccessfully', conference);
}).onConferenceParticipantJoined((participant)=>{ }).onConferenceParticipantJoined((participant)=>{
store.commit('conference/participantJoined', participant); store.commit('conference/participantJoined', participant);
participant.onMediaStream(()=>{
store.commit('conference/addRemoteMedia', participant.id);
})
participant.onMediaStarted(()=>{
store.commit('conference/addRemoteMedia', participant.id);
})
participant.onMediaRecovered(()=>{
store.commit('conference/addRemoteMedia', participant.id);
})
participant.onMediaEnded(()=>{
store.commit('conference/removeRemoteMedia', participant.id);
})
}).onConferenceParticipantLeft((participant)=>{ }).onConferenceParticipantLeft((participant)=>{
store.commit('conference/participantLeft', participant); store.commit('conference/participantLeft', participant);
}).onConferenceEvent((event)=>{ }).onConferenceEvent((event)=>{

@ -247,3 +247,27 @@ input.q-input-target
i i
margin 0 margin 0
.csc-conf-participant-cont
margin-bottom 20px
width 115px
height 115px
background white
.csc-conf-participants-item-title
position relative
background white
bottom 24px
text-align center
padding 0
background rgba(0, 0, 0, 0.5)
.q-card-title
color $primary
font-size 12px
line-height 24px
.csc-avatar-cont
height 100%
top 6px
.csc-media-cont
height 100% !important
width 100% !important
video
height: 100%;

Loading…
Cancel
Save