|
@@ -54,15 +54,33 @@
|
|
@if($client)
|
|
@if($client)
|
|
<div class="">
|
|
<div class="">
|
|
<div class="main-view mx-auto">
|
|
<div class="main-view mx-auto">
|
|
- <div id="self-view" class="full-view" :data-uid="myMediaServiceIdentifier" data-name="You" data-type="PRO"></div>
|
|
|
|
|
|
+ <div id="self-view" class="full-view"
|
|
|
|
+ :data-self="mainViewParticipant.self"
|
|
|
|
+ :data-uid="mainViewParticipant.uid"
|
|
|
|
+ :data-name="mainViewParticipant.name"
|
|
|
|
+ :data-type="mainViewParticipant.type"></div>
|
|
<div class="thumbs">
|
|
<div class="thumbs">
|
|
|
|
+ <div v-if="mainViewParticipant.uid !== myMediaServiceIdentifier"
|
|
|
|
+ :id="'remote-view-' + myMediaServiceIdentifier"
|
|
|
|
+ :data-self="true"
|
|
|
|
+ :data-uid="myMediaServiceIdentifier"
|
|
|
|
+ :data-name="'You'"
|
|
|
|
+ :data-type="'PRO'" {{-- TODO: change in FE4 --}}
|
|
|
|
+ :data-audio="myMedia && myMedia.isMicrophoneOn ? 'on' : 'off'"
|
|
|
|
+ v-on:click.prevent="showInCenterView(true, myMediaServiceIdentifier, 'You', 'PRO')"
|
|
|
|
+ class="remote-view thumb-view c-pointer">
|
|
|
|
+ <i v-show="!myMedia || !myMedia.isMicrophoneOn" class="fa fa-microphone-slash muted"></i>
|
|
|
|
+ </div>
|
|
<div v-for="participant in otherParticipants"
|
|
<div v-for="participant in otherParticipants"
|
|
- :id="'remote-view-' + participant.uid"
|
|
|
|
|
|
+ v-if="mainViewParticipant.uid !== (+participant.mediaServiceIdentifier)"
|
|
|
|
+ :id="'remote-view-' + participant.mediaServiceIdentifier"
|
|
|
|
+ :data-self="false"
|
|
:data-uid="participant.mediaServiceIdentifier"
|
|
:data-uid="participant.mediaServiceIdentifier"
|
|
:data-name="participant.displayName"
|
|
:data-name="participant.displayName"
|
|
:data-type="participant.participantType"
|
|
:data-type="participant.participantType"
|
|
:data-audio="participant.media && participant.media.isMicrophoneOn ? 'on' : 'off'"
|
|
:data-audio="participant.media && participant.media.isMicrophoneOn ? 'on' : 'off'"
|
|
- class="remote-view thumb-view">
|
|
|
|
|
|
+ v-on:click.prevent="showInCenterView(false, participant.mediaServiceIdentifier, participant.displayName, participant.participantType)"
|
|
|
|
+ class="remote-view thumb-view c-pointer">
|
|
<i v-show="!participant.media || !participant.media.isMicrophoneOn" class="fa fa-microphone-slash muted"></i>
|
|
<i v-show="!participant.media || !participant.media.isMicrophoneOn" class="fa fa-microphone-slash muted"></i>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@@ -182,6 +200,14 @@
|
|
unresolvedParticipants: [], // does not exist in otherParticipants, but came in via Agora
|
|
unresolvedParticipants: [], // does not exist in otherParticipants, but came in via Agora
|
|
unrenderedParticipantsTimer: false,
|
|
unrenderedParticipantsTimer: false,
|
|
unresolvedParticipantsTimer: false,
|
|
unresolvedParticipantsTimer: false,
|
|
|
|
+
|
|
|
|
+ // main-view & thumb views
|
|
|
|
+ mainViewParticipant: {
|
|
|
|
+ self: true,
|
|
|
|
+ uid: '',
|
|
|
|
+ type: 'PRO',
|
|
|
|
+ name: 'You',
|
|
|
|
+ },
|
|
},
|
|
},
|
|
methods: {
|
|
methods: {
|
|
|
|
|
|
@@ -249,10 +275,11 @@
|
|
this.meetingType = state.meetingType;
|
|
this.meetingType = state.meetingType;
|
|
// NOTE: this now comes from its own end-point (see below)
|
|
// NOTE: this now comes from its own end-point (see below)
|
|
// this.myMediaServiceToken = state.myMediaServiceToken;
|
|
// this.myMediaServiceToken = state.myMediaServiceToken;
|
|
- this.myMediaServiceIdentifier = state.myMediaServiceIdentifier;
|
|
|
|
|
|
+ this.myMediaServiceIdentifier = +state.myMediaServiceIdentifier;
|
|
this.otherParticipants = state.otherParticipants;
|
|
this.otherParticipants = state.otherParticipants;
|
|
|
|
|
|
if(_firstRun) {
|
|
if(_firstRun) {
|
|
|
|
+ this.mainViewParticipant.uid = +state.myMediaServiceIdentifier;
|
|
$.post('/api/meeting/refreshMyMediaServiceToken', (_data) => { // get new agora token
|
|
$.post('/api/meeting/refreshMyMediaServiceToken', (_data) => { // get new agora token
|
|
if(!this.hasError(_data)) {
|
|
if(!this.hasError(_data)) {
|
|
this.myMediaServiceToken = _data.data;
|
|
this.myMediaServiceToken = _data.data;
|
|
@@ -294,7 +321,7 @@
|
|
let existing = this.otherParticipants.filter(_participant => {
|
|
let existing = this.otherParticipants.filter(_participant => {
|
|
return _participant.uid === eventData.performer;
|
|
return _participant.uid === eventData.performer;
|
|
});
|
|
});
|
|
- if(!existing.length) this.otherParticipants.push(eventData);
|
|
|
|
|
|
+ if(!existing.length) this.otherParticipants.push(eventData.data);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
});
|
|
@@ -434,7 +461,7 @@
|
|
|
|
|
|
// Show own feed
|
|
// Show own feed
|
|
if(this.myCamera && this.myMedia.isCameraAcquired) {
|
|
if(this.myCamera && this.myMedia.isCameraAcquired) {
|
|
- this.myCamera.play($('#self-view')[0]);
|
|
|
|
|
|
+ this.myCamera.play($('#self-view')[0], {fit: 'contain'});
|
|
}
|
|
}
|
|
|
|
|
|
// init unrenderedParticipantsTimer and unresolvedParticipantsTimer
|
|
// init unrenderedParticipantsTimer and unresolvedParticipantsTimer
|
|
@@ -484,7 +511,7 @@
|
|
user.audioTrack.play();
|
|
user.audioTrack.play();
|
|
}
|
|
}
|
|
else if(mediaType === 'video' && participant.media.isCameraOn) {
|
|
else if(mediaType === 'video' && participant.media.isCameraOn) {
|
|
- user.videoTrack.play($('[data-uid="' + user.uid + '"]')[0]);
|
|
|
|
|
|
+ user.videoTrack.play($('[data-uid="' + user.uid + '"]')[0], {fit: 'contain'});
|
|
}
|
|
}
|
|
this.markUserAsRendered(user);
|
|
this.markUserAsRendered(user);
|
|
}
|
|
}
|
|
@@ -621,7 +648,46 @@
|
|
},
|
|
},
|
|
// end: actions that notify participants via socket
|
|
// end: actions that notify participants via socket
|
|
|
|
|
|
- // utils: start
|
|
|
|
|
|
+ // start: main view / thumb views
|
|
|
|
+ showInCenterView: function(_self, _uid, _name, _type) {
|
|
|
|
+ this.mainViewParticipant = {
|
|
|
|
+ self: _self,
|
|
|
|
+ uid: +_uid,
|
|
|
|
+ type: _type,
|
|
|
|
+ name: _name,
|
|
|
|
+ };
|
|
|
|
+ Vue.nextTick(() => {
|
|
|
|
+ this.refreshVideos();
|
|
|
|
+ });
|
|
|
|
+ },
|
|
|
|
+ refreshVideos: function() {
|
|
|
|
+ // play self (only video)
|
|
|
|
+ // no need to check camera/mic acquired/on etc. as only published tracks will appear here
|
|
|
|
+ for(let track in this.mediaServiceClient.localTracks) {
|
|
|
|
+ if(this.mediaServiceClient.localTracks.hasOwnProperty(track)) {
|
|
|
|
+ track = this.mediaServiceClient.localTracks[track];
|
|
|
|
+ if(track.trackMediaType === 'video') {
|
|
|
|
+ track.play($('[data-uid="' + this.myMediaServiceIdentifier + '"]')[0], {fit: 'contain'});
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // play others
|
|
|
|
+ for(let remoteParticipant in this.mediaServiceClient.remoteUsers) {
|
|
|
|
+ if(this.mediaServiceClient.remoteUsers.hasOwnProperty(remoteParticipant)) {
|
|
|
|
+ remoteParticipant = this.mediaServiceClient.remoteUsers[remoteParticipant];
|
|
|
|
+ if(remoteParticipant.hasAudio && remoteParticipant.audioTrack) {
|
|
|
|
+ remoteParticipant.audioTrack.play();
|
|
|
|
+ }
|
|
|
|
+ if(remoteParticipant.hasVideo && remoteParticipant.videoTrack) {
|
|
|
|
+ remoteParticipant.videoTrack.play($('[data-uid="' + remoteParticipant.uid + '"]')[0], {fit: 'contain'});
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ // end: main view / thumb views
|
|
|
|
+
|
|
|
|
+ // start: utils
|
|
hasError: function(_data) { // check and report error if exists via toastr
|
|
hasError: function(_data) { // check and report error if exists via toastr
|
|
let msg = 'Unknown error!';
|
|
let msg = 'Unknown error!';
|
|
if(_data) {
|
|
if(_data) {
|
|
@@ -631,7 +697,7 @@
|
|
toastr.error(msg);
|
|
toastr.error(msg);
|
|
return true;
|
|
return true;
|
|
}
|
|
}
|
|
- // utils: end
|
|
|
|
|
|
+ // end: utils
|
|
},
|
|
},
|
|
mounted: function () {
|
|
mounted: function () {
|
|
this.enterClientRoomAsPro();
|
|
this.enterClientRoomAsPro();
|