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

@ -2,7 +2,6 @@
<div
class="row justify-center items-center csc-conf-full-height"
>
<div
id="csc-conf-join-content"
: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)=>{
options.localMediaStream = this.getLocalMediaStream();
this.getNetwork().joinConference(options).then((conference)=>{
this.conference = conference;
resolve(conference);
}).catch((err)=>{
reject(err);
@ -146,12 +147,13 @@ export class ConferencePlugin {
}
getLocalParticipant() {
this.conference.getLocalParticipant();
return this.conference.getLocalParticipant();
}
getRemoteParticipant(id) {
this.conference.getRemoteParticipant(id);
return this.conference.getRemoteParticipant(id);
}
}
export default {

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

@ -25,7 +25,8 @@ export default {
joinError: null,
leaveState: RequestState.initiated,
leaveError: null,
participants: []
participants: [],
remoteMediaStreams: []
},
getters: {
username(state, getters, rootState, rootGetters) {
@ -78,7 +79,33 @@ export default {
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: (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: {
enableConferencing(state) {
@ -126,6 +153,20 @@ export default {
state.microphoneEnabled = 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) {
state.joinState = RequestState.requesting;
state.joinError = null;
@ -133,6 +174,7 @@ export default {
joinSucceeded(state) {
state.joinState = RequestState.succeeded;
state.joinError = null;
state.leaveState = null;
},
joinFailed(state, error) {
state.joinState = RequestState.failed;
@ -141,6 +183,7 @@ export default {
leaveRequesting(state) {
state.leaveState = RequestState.requesting;
state.leaveError = null;
state.joinState = null;
},
leaveSucceeded(state) {
state.leaveState = RequestState.succeeded;
@ -153,12 +196,16 @@ export default {
state.leaveError = error;
},
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) {
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);
}).onConferenceParticipantJoined((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)=>{
store.commit('conference/participantLeft', participant);
}).onConferenceEvent((event)=>{

@ -247,3 +247,27 @@ input.q-input-target
i
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