|
@@ -37,110 +37,50 @@
|
|
</button>
|
|
</button>
|
|
|
|
|
|
<div class="instruction-container">
|
|
<div class="instruction-container">
|
|
- <div class="mic-access-chrome-desktop border bg-light rounded mx-3 p-2 d-none">
|
|
|
|
|
|
+ <div class="mic-access-chrome-desktop border bg-light rounded mx-3 px-3 pt-3 pb-2 d-none">
|
|
<p><b>We were unable to access your microphone!</b></p>
|
|
<p><b>We were unable to access your microphone!</b></p>
|
|
- <p>To allow access, please tap the media icon (indicated in the figure below).</p>
|
|
|
|
- <img src="/img/mic-access-chrome-desktop.png" class="mw-100 mx-auto my-2 d-block">
|
|
|
|
|
|
+ <p>To allow access, please tap the blocked media icon in your browser's address bar (indicated in the figure below).</p>
|
|
|
|
+ <img src="/img/mic-access-chrome-desktop.png" class="mw-100 mx-auto mb-3 d-block">
|
|
|
|
+ <p class="mb-0">Once you have allowed access, please click <b>Start Video</b> again to retry.</p>
|
|
|
|
+ </div>
|
|
|
|
+ <div class="cam-access-chrome-desktop border bg-light rounded mx-3 px-3 pt-3 pb-2 d-none">
|
|
|
|
+ <p><b>We were unable to access your camera!</b></p>
|
|
|
|
+ <p>To allow access, please tap the blocked media icon in your browser's address bar (indicated in the figure below).</p>
|
|
|
|
+ <img src="/img/mic-access-chrome-desktop.png" class="mw-100 mx-auto mb-3 d-block">
|
|
<p class="mb-0">Once you have allowed access, please click <b>Start Video</b> again to retry.</p>
|
|
<p class="mb-0">Once you have allowed access, please click <b>Start Video</b> again to retry.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
- <div id="video-container" class="d-none">
|
|
|
|
|
|
+ <div id="video-container">
|
|
<div class="main-view mx-auto">
|
|
<div class="main-view mx-auto">
|
|
- <div id="self-view" class="full-view"
|
|
|
|
- :data-self="mainViewParticipant.self"
|
|
|
|
- :data-uid="mainViewParticipant.uid"
|
|
|
|
- :data-name="mainViewParticipant.name"
|
|
|
|
- :data-type="mainViewParticipant.type">
|
|
|
|
- <div class="user-type-indicator">
|
|
|
|
- <i v-if="mainViewParticipant.type === 'CLIENT_GUEST'" class="fa fa-user text-white"></i>
|
|
|
|
- <i v-if="mainViewParticipant.type === 'PRO'" class="fa fa-stethoscope text-white"></i>
|
|
|
|
- </div>
|
|
|
|
- <div class="media-status-indicator">
|
|
|
|
- <i v-show="!getMediaByMediaServiceId(mainViewParticipant.uid).isCameraOn"
|
|
|
|
- class="fa fa-video-slash muted ml-1"
|
|
|
|
- :class="!getMediaByMediaServiceId(mainViewParticipant.uid).isCameraAcquired ? 'text-danger' : 'text-white'"></i>
|
|
|
|
- <i v-show="!getMediaByMediaServiceId(mainViewParticipant.uid).isMicrophoneOn"
|
|
|
|
- class="fa fa-microphone-slash muted ml-1"
|
|
|
|
- :class="!getMediaByMediaServiceId(mainViewParticipant.uid).isMicrophoneAcquired ? 'text-danger' : 'text-white'"></i>
|
|
|
|
- </div>
|
|
|
|
- </div>
|
|
|
|
- <div class="thumbs">
|
|
|
|
- <div v-if="mainViewParticipant.uid !== myMediaServiceIdentifier"
|
|
|
|
- :id="'remote-view-' + myMediaServiceIdentifier"
|
|
|
|
- :data-self="true"
|
|
|
|
- :data-uid="myMediaServiceIdentifier"
|
|
|
|
- :data-name="'You (' + myName + ')'"
|
|
|
|
- :data-type="'PRO'" {{-- TODO: change in FE4 --}}
|
|
|
|
- :data-audio="myMedia && myMedia.isMicrophoneOn ? 'on' : 'off'"
|
|
|
|
- v-on:click.prevent="showInCenterView(true, myMediaServiceIdentifier, 'You (' + myName + ')', 'PRO')"
|
|
|
|
- class="remote-view thumb-view c-pointer">
|
|
|
|
- <div class="user-type-indicator">
|
|
|
|
- <i class="fa fa-stethoscope text-white"></i>
|
|
|
|
- </div>
|
|
|
|
- <div class="media-status-indicator">
|
|
|
|
- <i v-show="!myMedia || !myMedia.isCameraOn"
|
|
|
|
- class="fa fa-video-slash muted ml-1"
|
|
|
|
- :class="!myMedia || !myMedia.isCameraAcquired ? 'text-danger' : 'text-white'"></i>
|
|
|
|
- <i v-show="!myMedia || !myMedia.isMicrophoneOn"
|
|
|
|
- class="fa fa-microphone-slash muted ml-1"
|
|
|
|
- :class="!myMedia || !myMedia.isMicrophoneAcquired ? 'text-danger' : 'text-white'"></i>
|
|
|
|
- </div>
|
|
|
|
- </div>
|
|
|
|
- <div v-for="participant in otherParticipants"
|
|
|
|
- v-if="mainViewParticipant.uid !== (+participant.mediaServiceIdentifier)"
|
|
|
|
- :id="'remote-view-' + participant.mediaServiceIdentifier"
|
|
|
|
- :data-self="false"
|
|
|
|
- :data-uid="participant.mediaServiceIdentifier"
|
|
|
|
- :data-name="participant.displayName"
|
|
|
|
- :data-type="participant.participantType"
|
|
|
|
- :data-audio="participant.media && participant.media.isMicrophoneOn ? 'on' : 'off'"
|
|
|
|
- v-on:click.prevent="showInCenterView(false, participant.mediaServiceIdentifier, participant.displayName, participant.participantType)"
|
|
|
|
- class="remote-view thumb-view c-pointer">
|
|
|
|
- <div class="user-type-indicator">
|
|
|
|
- <i v-if="participant.participantType === 'CLIENT_GUEST'" class="fa fa-user text-white"></i>
|
|
|
|
- <i v-if="participant.participantType === 'PRO'" class="fa fa-stethoscope text-white"></i>
|
|
|
|
- </div>
|
|
|
|
- <div class="media-status-indicator">
|
|
|
|
- <i v-show="!participant.media || !participant.media.isCameraOn"
|
|
|
|
- class="fa fa-video-slash muted ml-1"
|
|
|
|
- :class="!participant.media || !participant.media.isCameraAcquired ? 'text-danger' : 'text-white'"></i>
|
|
|
|
- <i v-show="!participant.media || !participant.media.isMicrophoneOn"
|
|
|
|
- class="fa fa-microphone-slash muted ml-1"
|
|
|
|
- :class="!participant.media || !participant.media.isMicrophoneAcquired ? 'text-danger' : 'text-white'"></i>
|
|
|
|
- </div>
|
|
|
|
- </div>
|
|
|
|
- </div>
|
|
|
|
- <div class="call-actions d-flex align-items-center">
|
|
|
|
- <button class="btn btn-danger rounded-circle"
|
|
|
|
- title="Leave Call"
|
|
|
|
- v-on:click.prevent="leaveClientRoom()">
|
|
|
|
- <i class="fa fa-phone"></i>
|
|
|
|
- </button>
|
|
|
|
- <button v-if="myMedia.isCameraOn" class="btn btn-default bg-light border rounded-circle"
|
|
|
|
- title="Stop Camera"
|
|
|
|
- v-on:click.prevent="myCameraIsOff()">
|
|
|
|
- <i class="fa fa-video"></i>
|
|
|
|
- </button>
|
|
|
|
- <button v-if="!myMedia.isCameraOn" class="btn btn-secondary rounded-circle"
|
|
|
|
- title="Start Camera"
|
|
|
|
- v-on:click.prevent="myCameraIsOn()">
|
|
|
|
- <i class="fa fa-video-slash"></i>
|
|
|
|
- </button>
|
|
|
|
- <button v-if="myMedia.isMicrophoneOn" class="btn btn-default bg-light border rounded-circle"
|
|
|
|
- title="Stop Microphone"
|
|
|
|
- v-on:click.prevent="myMicrophoneIsOff()">
|
|
|
|
- <i class="fa fa-microphone"></i>
|
|
|
|
- </button>
|
|
|
|
- <button v-if="!myMedia.isMicrophoneOn" class="btn btn-secondary rounded-circle"
|
|
|
|
- title="Start Microphone"
|
|
|
|
- v-on:click.prevent="myMicrophoneIsOn()">
|
|
|
|
- <i class="fa fa-microphone-slash"></i>
|
|
|
|
- </button>
|
|
|
|
- </div>
|
|
|
|
|
|
+ <div id="self-view" class="video-view"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
+<!-- <div class="call-actions d-none align-items-center">
|
|
|
|
+ <button class="btn btn-danger rounded-circle"
|
|
|
|
+ title="Leave Call">
|
|
|
|
+ <i class="fa fa-phone"></i>
|
|
|
|
+ </button>
|
|
|
|
+ <button v-if="myMedia.isCameraOn" class="btn btn-default bg-light border rounded-circle"
|
|
|
|
+ title="Stop Camera">
|
|
|
|
+ <i class="fa fa-video"></i>
|
|
|
|
+ </button>
|
|
|
|
+ <button v-if="!myMedia.isCameraOn" class="btn btn-secondary rounded-circle"
|
|
|
|
+ title="Start Camera">
|
|
|
|
+ <i class="fa fa-video-slash"></i>
|
|
|
|
+ </button>
|
|
|
|
+ <button v-if="myMedia.isMicrophoneOn" class="btn btn-default bg-light border rounded-circle"
|
|
|
|
+ title="Stop Microphone"
|
|
|
|
+ v-on:click.prevent="myMicrophoneIsOff()">
|
|
|
|
+ <i class="fa fa-microphone"></i>
|
|
|
|
+ </button>
|
|
|
|
+ <button v-if="!myMedia.isMicrophoneOn" class="btn btn-secondary rounded-circle"
|
|
|
|
+ title="Start Microphone">
|
|
|
|
+ <i class="fa fa-microphone-slash"></i>
|
|
|
|
+ </button>
|
|
|
|
+ </div>-->
|
|
|
|
+
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<script>
|
|
<script>
|
|
@@ -247,6 +187,22 @@
|
|
// create client
|
|
// create client
|
|
this.mediaServiceClient = AgoraRTC.createClient({mode: 'rtc', codec: 'vp8'});
|
|
this.mediaServiceClient = AgoraRTC.createClient({mode: 'rtc', codec: 'vp8'});
|
|
|
|
|
|
|
|
+ // acquire devices
|
|
|
|
+ this.attemptToAcquireMicrophone(() => {
|
|
|
|
+ this.attemptToAcquireCamera(() => {
|
|
|
|
+ console.log('ALIX: Hurrah! Mic and camera both acquired :)');
|
|
|
|
+
|
|
|
|
+ // go to video UI
|
|
|
|
+ $('#btn-start-video').removeClass('d-block').addClass('d-none');
|
|
|
|
+ $('#video-container').removeClass('d-none').addClass('d-block');
|
|
|
|
+ $('#self-view').height($('#self-view').width() * 0.75);
|
|
|
|
+ this.myCamera.play($('#self-view')[0], {fit: 'contain'});
|
|
|
|
+ })
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ attemptToAcquireMicrophone: function(_done) {
|
|
AgoraRTC.onMicrophoneChanged = (_info) => {
|
|
AgoraRTC.onMicrophoneChanged = (_info) => {
|
|
console.log("ALIX: microphone changed!", _info.state, _info.device);
|
|
console.log("ALIX: microphone changed!", _info.state, _info.device);
|
|
if(_info.state === 'ACTIVE') {
|
|
if(_info.state === 'ACTIVE') {
|
|
@@ -260,6 +216,11 @@
|
|
console.log('ALIX: microphone acquisition attempt completed');
|
|
console.log('ALIX: microphone acquisition attempt completed');
|
|
console.log('ALIX: (reactive) isMicrophoneAcquired = ', this.meetingData.myMedia.isMicrophoneAcquired);
|
|
console.log('ALIX: (reactive) isMicrophoneAcquired = ', this.meetingData.myMedia.isMicrophoneAcquired);
|
|
console.log('ALIX: (reactive) isMicrophoneOn = ', this.meetingData.myMedia.isMicrophoneOn);
|
|
console.log('ALIX: (reactive) isMicrophoneOn = ', this.meetingData.myMedia.isMicrophoneOn);
|
|
|
|
+
|
|
|
|
+ // if all good, allow to proceed
|
|
|
|
+ if(this.myMicrophone && this.meetingData.myMedia.isMicrophoneAcquired) {
|
|
|
|
+ _done.call(this);
|
|
|
|
+ }
|
|
});
|
|
});
|
|
}
|
|
}
|
|
};
|
|
};
|
|
@@ -269,11 +230,15 @@
|
|
console.log('ALIX: microphone acquisition attempt completed');
|
|
console.log('ALIX: microphone acquisition attempt completed');
|
|
console.log('ALIX: (proactive) isMicrophoneAcquired = ', this.meetingData.myMedia.isMicrophoneAcquired);
|
|
console.log('ALIX: (proactive) isMicrophoneAcquired = ', this.meetingData.myMedia.isMicrophoneAcquired);
|
|
console.log('ALIX: (proactive) isMicrophoneOn = ', this.meetingData.myMedia.isMicrophoneOn);
|
|
console.log('ALIX: (proactive) isMicrophoneOn = ', this.meetingData.myMedia.isMicrophoneOn);
|
|
- });
|
|
|
|
|
|
|
|
|
|
+ // if all good, allow to proceed
|
|
|
|
+ if(this.myMicrophone && this.meetingData.myMedia.isMicrophoneAcquired) {
|
|
|
|
+ _done.call(this);
|
|
|
|
+ }
|
|
|
|
+ });
|
|
},
|
|
},
|
|
|
|
|
|
- acquireMicrophone: async function(_deviceId = false) {
|
|
|
|
|
|
+ acquireMicrophone: async function() {
|
|
|
|
|
|
// if already acquired, ignore
|
|
// if already acquired, ignore
|
|
if(this.myMicrophone && this.meetingData.myMedia.isMicrophoneAcquired) {
|
|
if(this.myMicrophone && this.meetingData.myMedia.isMicrophoneAcquired) {
|
|
@@ -292,7 +257,7 @@
|
|
// TODO: notify others via WS
|
|
// TODO: notify others via WS
|
|
|
|
|
|
this.myMicrophone.setEnabled(true);
|
|
this.myMicrophone.setEnabled(true);
|
|
- this.myMicrophone.setVolume(1000);
|
|
|
|
|
|
+ this.myMicrophone.setVolume(1000); // 1000 is the max allowed value
|
|
this.meetingData.myMedia.isMicrophoneOn = true;
|
|
this.meetingData.myMedia.isMicrophoneOn = true;
|
|
console.log('ALIX: microphone is ON and not on mute :)');
|
|
console.log('ALIX: microphone is ON and not on mute :)');
|
|
// TODO: log
|
|
// TODO: log
|
|
@@ -312,20 +277,79 @@
|
|
}
|
|
}
|
|
},
|
|
},
|
|
|
|
|
|
|
|
+ attemptToAcquireCamera: function(_done) {
|
|
|
|
+ AgoraRTC.onCameraChanged = (_info) => {
|
|
|
|
+ console.log("ALIX: camera changed!", _info.state, _info.device);
|
|
|
|
+ if(_info.state === 'ACTIVE') {
|
|
|
|
+
|
|
|
|
+ if(!this.myCamera || !this.meetingData.myMedia.isCameraAcquired) {
|
|
|
|
+ window.location.reload();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // reactive acquisition (because user later granted access)
|
|
|
|
+ this.acquireCamera().then(() => {
|
|
|
|
+ console.log('ALIX: camera acquisition attempt completed');
|
|
|
|
+ console.log('ALIX: (reactive) isCameraAcquired = ', this.meetingData.myMedia.isCameraAcquired);
|
|
|
|
+ console.log('ALIX: (reactive) isCameraOn = ', this.meetingData.myMedia.isCameraOn);
|
|
|
|
+
|
|
|
|
+ // if all good, allow to proceed
|
|
|
|
+ if(this.myCamera && this.meetingData.myMedia.isCameraAcquired) {
|
|
|
|
+ _done.call(this);
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ // proactive acquisition (already allowed OR user clicked "Allow" when prompted
|
|
|
|
+ this.acquireCamera().then(() => {
|
|
|
|
+ console.log('ALIX: camera acquisition attempt completed');
|
|
|
|
+ console.log('ALIX: (proactive) isCameraAcquired = ', this.meetingData.myMedia.isCameraAcquired);
|
|
|
|
+ console.log('ALIX: (proactive) isCameraOn = ', this.meetingData.myMedia.isCameraOn);
|
|
|
|
+
|
|
|
|
+ // if all good, allow to proceed
|
|
|
|
+ if(this.myCamera && this.meetingData.myMedia.isCameraAcquired) {
|
|
|
|
+ _done.call(this);
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+ },
|
|
|
|
+
|
|
acquireCamera: async function() {
|
|
acquireCamera: async function() {
|
|
- this.myMedia.isCameraAcquired = false;
|
|
|
|
- this.myMedia.isCameraOn = false;
|
|
|
|
|
|
+
|
|
|
|
+ // if already acquired, ignore
|
|
|
|
+ if(this.myCamera && this.meetingData.myMedia.isCameraAcquired) {
|
|
|
|
+ console.log("ALIX: Skipping camera acquisition..")
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ this.meetingData.myMedia.isCameraAcquired = false;
|
|
|
|
+ this.meetingData.myMedia.isCameraOn = false;
|
|
try {
|
|
try {
|
|
- @if(config('app.agora_mode') === 'screen') // testing
|
|
|
|
- this.myCamera = await AgoraRTC.createScreenVideoTrack();
|
|
|
|
- @else
|
|
|
|
- this.myCamera = await AgoraRTC.createCameraVideoTrack({
|
|
|
|
|
|
+ this.myCamera = await AgoraRTC.createCameraVideoTrack({
|
|
optimizationMode: "motion"
|
|
optimizationMode: "motion"
|
|
});
|
|
});
|
|
- @endif
|
|
|
|
- this.myMedia.isCameraAcquired = true;
|
|
|
|
|
|
+
|
|
|
|
+ console.log('ALIX: acquired camera :)');
|
|
|
|
+ this.meetingData.myMedia.isCameraAcquired = true;
|
|
|
|
+ // TODO: log
|
|
|
|
+ // TODO: notify others via WS
|
|
|
|
+
|
|
|
|
+ this.myCamera.setEnabled(true);
|
|
|
|
+ this.meetingData.myMedia.isCameraOn = true;
|
|
|
|
+ console.log('ALIX: camera is ON :)');
|
|
|
|
+ // TODO: log
|
|
|
|
+ // TODO: notify others via WS
|
|
|
|
+
|
|
} catch (e) {
|
|
} catch (e) {
|
|
- console.log('ALIX: error in getting camera');
|
|
|
|
|
|
+ console.error('ALIX: could not acquire camera');
|
|
|
|
+
|
|
|
|
+ this.meetingData.myMedia.isCameraAcquired = false;
|
|
|
|
+ this.meetingData.myMedia.isCameraOn = false;
|
|
|
|
+ // TODO: log
|
|
|
|
+ // TODO: notify others via WS
|
|
|
|
+
|
|
|
|
+ $('#btn-start-video').removeClass('d-block').addClass('d-none');
|
|
|
|
+ // TODO: Use device/browser specific instruction & image
|
|
|
|
+ $('.cam-access-chrome-desktop').removeClass('d-none').addClass('d-block');
|
|
}
|
|
}
|
|
},
|
|
},
|
|
|
|
|
|
@@ -379,643 +403,5 @@
|
|
}).call(window);
|
|
}).call(window);
|
|
</script>
|
|
</script>
|
|
|
|
|
|
-
|
|
|
|
-<script class="d-none">
|
|
|
|
- (function () {
|
|
|
|
- window.proCallComponent = new Vue({
|
|
|
|
- el: '#proCallComponentFF',
|
|
|
|
- delimiters: ['@{{', '}}'],
|
|
|
|
- data: {
|
|
|
|
-
|
|
|
|
- // main model - declare up-front to make reactive - override with server data on mount
|
|
|
|
- amIInAMeeting: false,
|
|
|
|
- meetingType: '', // PRO/CLIENT,
|
|
|
|
- inMeetingForClientUid: '',
|
|
|
|
- inMeetingForClient: {
|
|
|
|
- clientMediaServiceRoomIdentifier: '',
|
|
|
|
- uid: '',
|
|
|
|
- displayName: '',
|
|
|
|
- dob: '',
|
|
|
|
- },
|
|
|
|
- myMediaServiceToken: '',
|
|
|
|
- myMediaServiceIdentifier: '',
|
|
|
|
- myMedia: {
|
|
|
|
- isCameraAcquired: false,
|
|
|
|
- isCameraOn: false,
|
|
|
|
- isMicrophoneAcquired: false,
|
|
|
|
- isMicrophoneOn: false,
|
|
|
|
- },
|
|
|
|
- otherParticipants: [
|
|
|
|
- {
|
|
|
|
- participantType: '', // PRO/CLIENT_GUEST,
|
|
|
|
- uid: '',
|
|
|
|
- mediaServiceIdentifier: '',
|
|
|
|
- displayName: '',
|
|
|
|
- media: {
|
|
|
|
- isCameraAcquired: false,
|
|
|
|
- isCameraOn: false,
|
|
|
|
- isMicrophoneAcquired: false,
|
|
|
|
- isMicrophoneOn: false,
|
|
|
|
- },
|
|
|
|
- awayMessage: '',
|
|
|
|
- deviceType: '',
|
|
|
|
- isMeetingAccessGranted: '',
|
|
|
|
- isSocketConnected: '',
|
|
|
|
- }
|
|
|
|
- ],
|
|
|
|
- awayMessage: '',
|
|
|
|
- myName: '{{ $performer->pro->displayName() }}',
|
|
|
|
-
|
|
|
|
- // agora
|
|
|
|
- mediaServiceClient: null, // set on agora init
|
|
|
|
- appId: '{{ config('app.agora_appid') }}',
|
|
|
|
- channel: '', // set on mount
|
|
|
|
- myMicrophone: null,
|
|
|
|
- myCamera: null,
|
|
|
|
- appMode: 'name', // Agora needs a user-gesture to init correctly
|
|
|
|
-
|
|
|
|
- // sockets
|
|
|
|
- backendWsURL: 'http://localhost:8080/ws', // {{ config('app.backend_ws_url') }}',
|
|
|
|
- socketClient: null,
|
|
|
|
-
|
|
|
|
- // other
|
|
|
|
- ringer: {{ $pro->is_ring_on ? 'true' : 'false' }},
|
|
|
|
-
|
|
|
|
- // agora <-> WS sync
|
|
|
|
- unrenderedParticipants: [], // exists in otherParticipants, but not yet in DOM
|
|
|
|
- unresolvedParticipants: [], // does not exist in otherParticipants, but came in via Agora
|
|
|
|
- unrenderedParticipantsTimer: false,
|
|
|
|
- unresolvedParticipantsTimer: false,
|
|
|
|
-
|
|
|
|
- // main-view participant
|
|
|
|
- mainViewParticipant: {
|
|
|
|
- self: true,
|
|
|
|
- uid: '',
|
|
|
|
- type: 'PRO',
|
|
|
|
- name: 'You ({{ $performer->pro->displayName() }})',
|
|
|
|
- },
|
|
|
|
- },
|
|
|
|
- methods: {
|
|
|
|
-
|
|
|
|
- // start: main flow
|
|
|
|
- enterClientRoomAsPro: function () {
|
|
|
|
- @if($client)
|
|
|
|
- this.socketClient.send("/app/leaveClientRoom", {},
|
|
|
|
- JSON.stringify({sessionKey: '{{$performer->session_key}}'})
|
|
|
|
- );
|
|
|
|
- window.setTimeout(() => {
|
|
|
|
- $.post('/api/meeting/enterClientRoomAsPro', {clientUid: '{{ $client->uid }}'}, (_data) => {
|
|
|
|
- if (!this.hasError(_data)) {
|
|
|
|
- this.appMode = 'video';
|
|
|
|
- this.getMeetingInfo(true);
|
|
|
|
- }
|
|
|
|
- });
|
|
|
|
- }, 250);
|
|
|
|
- @endif
|
|
|
|
- },
|
|
|
|
- getMeetingInfo: function (_firstRun = false) {
|
|
|
|
- $.post('/api/meeting/getMyMeeting', (_data) => {
|
|
|
|
- if (_data && _data.success) {
|
|
|
|
- let state = _data.data;
|
|
|
|
- console.log(state);
|
|
|
|
-
|
|
|
|
- // overwrite model data
|
|
|
|
- this.amIInAMeeting = state.amIInAMeeting;
|
|
|
|
- this.inMeetingForClientUid = state.inMeetingForClientUid;
|
|
|
|
- this.inMeetingForClient.clientMediaServiceRoomIdentifier =
|
|
|
|
- state.inMeetingForClient.clientMediaServiceRoomIdentifier;
|
|
|
|
- this.inMeetingForClient.uid = state.inMeetingForClient.uid;
|
|
|
|
- this.inMeetingForClient.displayName = state.inMeetingForClient.displayName;
|
|
|
|
- this.inMeetingForClient.dob = state.inMeetingForClient.dob;
|
|
|
|
- this.meetingType = state.meetingType;
|
|
|
|
- // NOTE: this now comes from its own end-point (see below)
|
|
|
|
- // this.myMediaServiceToken = state.myMediaServiceToken;
|
|
|
|
- this.myMediaServiceIdentifier = +state.myMediaServiceIdentifier;
|
|
|
|
- this.otherParticipants = state.otherParticipants;
|
|
|
|
-
|
|
|
|
- if (_firstRun) {
|
|
|
|
- this.mainViewParticipant.uid = +state.myMediaServiceIdentifier;
|
|
|
|
- $.post('/api/meeting/refreshMyMediaServiceToken', (_data) => { // get new agora token
|
|
|
|
- if (!this.hasError(_data)) {
|
|
|
|
- this.myMediaServiceToken = _data.data;
|
|
|
|
- this.channel = this.inMeetingForClient.clientMediaServiceRoomIdentifier;
|
|
|
|
- this.initMediaService();
|
|
|
|
- }
|
|
|
|
- }, 'json');
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- console.log(this.$data);
|
|
|
|
- }
|
|
|
|
- }, 'json');
|
|
|
|
- },
|
|
|
|
- registerSocket: function (_done) {
|
|
|
|
- let socket = new SockJS(this.backendWsURL);
|
|
|
|
- this.socketClient = Stomp.over(socket);
|
|
|
|
- this.socketClient.connect({}, (frame) => {
|
|
|
|
- console.log('Connected: ' + frame);
|
|
|
|
- this.initSocketListeners(); // init listeners
|
|
|
|
- this.socketClient.send("/app/register", {}, // register self
|
|
|
|
- JSON.stringify({
|
|
|
|
- sessionKey: '{{$performer->session_key}}'
|
|
|
|
- })
|
|
|
|
- );
|
|
|
|
- window.setInterval(() => {
|
|
|
|
- this.socketClient.send("/app/heartbeat", {},
|
|
|
|
- JSON.stringify({sessionKey: '{{ request()->cookie('sessionKey') }}'})
|
|
|
|
- );
|
|
|
|
- }, 5000);
|
|
|
|
- });
|
|
|
|
- },
|
|
|
|
- initSocketListeners: function () {
|
|
|
|
-
|
|
|
|
- function _isSelf(_eventData) {
|
|
|
|
- return _eventData.performer === '{{ $session->uid }}';
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- function _setParticipantProperty(_message, _propertyName, _valueKeyName) {
|
|
|
|
- if (_message && _message.body) {
|
|
|
|
- let eventData = JSON.parse(_message.body);
|
|
|
|
- if (!_isSelf(eventData) && eventData.data) {
|
|
|
|
- for (let i = 0; i < this.otherParticipants.length; i++) {
|
|
|
|
- if (this.otherParticipants[i].uid === eventData.performer) {
|
|
|
|
- this.otherParticipants[i][_propertyName] = eventData.data[_valueKeyName];
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- function _setParticipantMediaProperty(_message, _propertyName, _value) {
|
|
|
|
- if (_message && _message.body) {
|
|
|
|
- let eventData = JSON.parse(_message.body);
|
|
|
|
- if (!_isSelf(eventData) && eventData.data) {
|
|
|
|
- for (let i = 0; i < this.otherParticipants.length; i++) {
|
|
|
|
- if (this.otherParticipants[i].uid === eventData.performer) {
|
|
|
|
- this.otherParticipants[i].media[_propertyName] = _value;
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- this.socketClient.subscribe("/user/topic/newParticipant", (message) => {
|
|
|
|
- console.log("newParticipant received:", message.body);
|
|
|
|
- if (message && message.body) {
|
|
|
|
- let eventData = JSON.parse(message.body);
|
|
|
|
- if (!_isSelf(eventData) && eventData.data) {
|
|
|
|
- let existing = this.otherParticipants.filter(_participant => {
|
|
|
|
- return _participant.uid === eventData.performer;
|
|
|
|
- });
|
|
|
|
- if (!existing.length) this.otherParticipants.push(eventData.data);
|
|
|
|
- Vue.nextTick(() => {
|
|
|
|
- this.refreshVideos();
|
|
|
|
- });
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- });
|
|
|
|
-
|
|
|
|
- this.socketClient.subscribe("/user/topic/myMicrophoneIsAcquired", (message) => {
|
|
|
|
- console.log("myMicrophoneIsAcquired received:", message.body);
|
|
|
|
- _setParticipantMediaProperty.call(this, message, 'isMicrophoneAcquired', true);
|
|
|
|
- });
|
|
|
|
-
|
|
|
|
- this.socketClient.subscribe("/user/topic/myMicrophoneIsNotAcquired", (message) => {
|
|
|
|
- console.log("myMicrophoneIsNotAcquired received:", message.body);
|
|
|
|
- _setParticipantMediaProperty.call(this, message, 'isMicrophoneAcquired', false);
|
|
|
|
- _setParticipantMediaProperty.call(this, message, 'isMicrophoneOn', false);
|
|
|
|
- });
|
|
|
|
-
|
|
|
|
- this.socketClient.subscribe("/user/topic/myMicrophoneIsOn", (message) => {
|
|
|
|
- console.log("myMicrophoneIsOn received:", message.body);
|
|
|
|
- _setParticipantMediaProperty.call(this, message, 'isMicrophoneOn', true);
|
|
|
|
- _setParticipantMediaProperty.call(this, message, 'isMicrophoneAcquired', true);
|
|
|
|
- });
|
|
|
|
-
|
|
|
|
- this.socketClient.subscribe("/user/topic/myMicrophoneIsOff", (message) => {
|
|
|
|
- console.log("ALIX myMicrophoneIsOff received:", message.body);
|
|
|
|
- _setParticipantMediaProperty.call(this, message, 'isMicrophoneOn', false);
|
|
|
|
- });
|
|
|
|
-
|
|
|
|
- this.socketClient.subscribe("/user/topic/myCameraIsAcquired", (message) => {
|
|
|
|
- console.log("myCameraIsAcquired received:", message.body);
|
|
|
|
- _setParticipantMediaProperty.call(this, message, 'isCameraAcquired', true);
|
|
|
|
- });
|
|
|
|
-
|
|
|
|
- this.socketClient.subscribe("/user/topic/myCameraIsNotAcquired", (message) => {
|
|
|
|
- console.log("myCameraIsNotAcquired received:", message.body);
|
|
|
|
- _setParticipantMediaProperty.call(this, message, 'isCameraAcquired', false);
|
|
|
|
- _setParticipantMediaProperty.call(this, message, 'isCameraOn', false);
|
|
|
|
- });
|
|
|
|
-
|
|
|
|
- this.socketClient.subscribe("/user/topic/myCameraIsOn", (message) => {
|
|
|
|
- console.log("myCameraIsOn received:", message.body);
|
|
|
|
- _setParticipantMediaProperty.call(this, message, 'isCameraOn', true);
|
|
|
|
- _setParticipantMediaProperty.call(this, message, 'isCameraAcquired', true);
|
|
|
|
- });
|
|
|
|
-
|
|
|
|
- this.socketClient.subscribe("/user/topic/myCameraIsOff", (message) => {
|
|
|
|
- console.log("myCameraIsOff received:", message.body);
|
|
|
|
- _setParticipantMediaProperty.call(this, message, 'isCameraOn', false);
|
|
|
|
- });
|
|
|
|
-
|
|
|
|
- this.socketClient.subscribe("/user/topic/editMyName", (message) => {
|
|
|
|
- console.log("editMyName received:", message.body);
|
|
|
|
- _setParticipantProperty.call(this, message, 'displayName', 'myName');
|
|
|
|
- });
|
|
|
|
-
|
|
|
|
- this.socketClient.subscribe("/user/topic/setMyAwayMessage", (message) => {
|
|
|
|
- console.log("setMyAwayMessage received:", message.body);
|
|
|
|
- });
|
|
|
|
-
|
|
|
|
- this.socketClient.subscribe("/user/topic/removeMyAwayMessage", (message) => {
|
|
|
|
- console.log("removeMyAwayMessage received:", message.body);
|
|
|
|
- });
|
|
|
|
-
|
|
|
|
- this.socketClient.subscribe("/user/topic/leaveClientRoom", (message) => {
|
|
|
|
- console.log("leaveClientRoom received:", message.body);
|
|
|
|
- if (message && message.body) {
|
|
|
|
- let eventData = JSON.parse(message.body);
|
|
|
|
- if (!_isSelf(eventData) && eventData.data) {
|
|
|
|
-
|
|
|
|
- // if the participant who left is in center view, switch center view to self
|
|
|
|
- for (let i = 0; i < this.otherParticipants.length; i++) {
|
|
|
|
- if (this.otherParticipants[i].uid === eventData.performer) {
|
|
|
|
- if (this.mainViewParticipant.uid === (+this.otherParticipants[i].mediaServiceIdentifier)) {
|
|
|
|
- this.showInCenterView(true, this.myMediaServiceIdentifier, 'You (' + this.myName + ')', 'PRO');
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- this.otherParticipants = this.otherParticipants.filter(_participant => {
|
|
|
|
- return _participant.uid !== eventData.performer;
|
|
|
|
- });
|
|
|
|
-
|
|
|
|
- Vue.nextTick(() => {
|
|
|
|
- this.refreshVideos();
|
|
|
|
- });
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- });
|
|
|
|
-
|
|
|
|
- },
|
|
|
|
- initMediaService: function () {
|
|
|
|
-
|
|
|
|
- this.mediaServiceClient = AgoraRTC.createClient({mode: 'rtc', codec: 'vp8'});
|
|
|
|
-
|
|
|
|
- async function _acquireMicrophone() {
|
|
|
|
- this.myMedia.isMicrophoneAcquired = false;
|
|
|
|
- this.myMedia.isMicrophoneOn = false;
|
|
|
|
- try {
|
|
|
|
- this.myMicrophone = await AgoraRTC.createMicrophoneAudioTrack();
|
|
|
|
- this.myMedia.isMicrophoneAcquired = true;
|
|
|
|
- } catch (e) {
|
|
|
|
- console.log('ALIX: error in getting mic');
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- async function _acquireCamera() {
|
|
|
|
- this.myMedia.isCameraAcquired = false;
|
|
|
|
- this.myMedia.isCameraOn = false;
|
|
|
|
- try {
|
|
|
|
- @if(config('app.agora_mode') === 'screen') // testing
|
|
|
|
- this.myCamera = await AgoraRTC.createScreenVideoTrack();
|
|
|
|
- @else
|
|
|
|
- this.myCamera = await AgoraRTC.createCameraVideoTrack({
|
|
|
|
- optimizationMode: "motion"
|
|
|
|
- });
|
|
|
|
- @endif
|
|
|
|
- this.myMedia.isCameraAcquired = true;
|
|
|
|
- } catch (e) {
|
|
|
|
- console.log('ALIX: error in getting camera');
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- async function _initMediaServiceEvents() {
|
|
|
|
- this.mediaServiceClient.on('user-joined', user => {
|
|
|
|
- // do nothing, newParticipant logic handled via WS
|
|
|
|
- });
|
|
|
|
- this.mediaServiceClient.on('user-left', user => {
|
|
|
|
- // do nothing, leaveClientRoom logic handled via WS
|
|
|
|
- });
|
|
|
|
- this.mediaServiceClient.on('user-published', async (user, mediaType) => {
|
|
|
|
- console.log('ALIX user-published', user);
|
|
|
|
- await this.mediaServiceClient.subscribe(user, mediaType)
|
|
|
|
- this.attemptToPlayParticipantMedia(user, mediaType);
|
|
|
|
- window.setTimeout(() => {
|
|
|
|
- this.refreshVideos();
|
|
|
|
- }, 500);
|
|
|
|
- });
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- async function _initMediaService() {
|
|
|
|
-
|
|
|
|
- await _acquireMicrophone.call(this); // get mic
|
|
|
|
- await _acquireCamera.call(this); // get cam (or screen for testing)
|
|
|
|
-
|
|
|
|
- if (!this.myMicrophone && !this.myCamera) {
|
|
|
|
- alert('Do you have camera/mic? Unable to hear or see you.');
|
|
|
|
- // return; // allow to proceed without any device!
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- await _initMediaServiceEvents.call(this);
|
|
|
|
-
|
|
|
|
- // Show own feed
|
|
|
|
- if (this.myCamera && this.myMedia.isCameraAcquired) {
|
|
|
|
- this.myCamera.play($('#self-view')[0], {fit: 'contain'});
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // init unrenderedParticipantsTimer and unresolvedParticipantsTimer
|
|
|
|
- this.initUnrenderedParticipantsTimer();
|
|
|
|
- this.initUnresolvedParticipantsTimer();
|
|
|
|
-
|
|
|
|
- await this.mediaServiceClient.join( // join agora channel
|
|
|
|
- this.appId,
|
|
|
|
- this.channel,
|
|
|
|
- this.myMediaServiceToken,
|
|
|
|
- +this.myMediaServiceIdentifier
|
|
|
|
- );
|
|
|
|
-
|
|
|
|
- if (this.myMicrophone || this.myCamera) {
|
|
|
|
- await this.mediaServiceClient.publish( // publish audio/video
|
|
|
|
- [this.myMicrophone, this.myCamera].filter(Boolean)
|
|
|
|
- );
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // notify others about my camera status
|
|
|
|
- if (this.myCamera && this.myMedia.isCameraAcquired) {
|
|
|
|
- this.myCameraIsAcquired();
|
|
|
|
- this.myCameraIsOn();
|
|
|
|
- } else {
|
|
|
|
- this.myCameraIsNotAcquired();
|
|
|
|
- this.myCameraIsOff();
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // notify others about my microphone status
|
|
|
|
- if (this.myMicrophone && this.myMedia.isMicrophoneAcquired) {
|
|
|
|
- this.myMicrophoneIsAcquired();
|
|
|
|
- this.myMicrophoneIsOn();
|
|
|
|
- } else {
|
|
|
|
- this.myMicrophoneIsNotAcquired();
|
|
|
|
- this.myMicrophoneIsOff();
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- _initMediaService.call(this);
|
|
|
|
- },
|
|
|
|
- attemptToPlayParticipantMedia: function (user, mediaType) {
|
|
|
|
- // LOGIC
|
|
|
|
- // attemptToPlayParticipantMedia
|
|
|
|
- // if user already in otherParticipants
|
|
|
|
- // if user's thumb already rendered
|
|
|
|
- // if yes, check participant's isCameraOn is true
|
|
|
|
- // if yes, play participant's video in his thumb
|
|
|
|
- // else store "user" in unrenderedParticipants
|
|
|
|
- // and keep retrying after 500mx (max 2 times) - i.e. give vue a cycle or 2 to render thumb
|
|
|
|
- // else store "user" in unresolvedParticipants
|
|
|
|
- // and keep retrying after 500ms (max 10 times) till resolved - i.e. give WS time to receive the newParticipant event
|
|
|
|
- let participant = this.otherParticipants.filter(function (_participant) {
|
|
|
|
- return (+_participant.mediaServiceIdentifier) === user.uid;
|
|
|
|
- });
|
|
|
|
- if (participant && participant.length) {
|
|
|
|
- participant = participant[0];
|
|
|
|
- if ($('[data-uid="' + participant.mediaServiceIdentifier + '"]').length) {
|
|
|
|
- if (mediaType === 'audio' && user.hasAudio && user.audioTrack) {
|
|
|
|
- participant.media.isMicrophoneAcquired = true;
|
|
|
|
- participant.media.isMicrophoneOn = true;
|
|
|
|
- user.audioTrack.play();
|
|
|
|
- } else if (mediaType === 'video' && user.hasVideo && user.videoTrack) {
|
|
|
|
- participant.media.isCameraAcquired = true;
|
|
|
|
- participant.media.isCameraOn = true;
|
|
|
|
- user.videoTrack.play($('[data-uid="' + user.uid + '"]')[0], {fit: 'contain'});
|
|
|
|
- }
|
|
|
|
- this.markUserAsRendered(user);
|
|
|
|
- } else {
|
|
|
|
- console.warn('Thumb not yet in DOM for participant!', user.uid);
|
|
|
|
- this.markUserAsUnrendered(user, mediaType);
|
|
|
|
- }
|
|
|
|
- this.markUserAsResolved(user);
|
|
|
|
- } else {
|
|
|
|
- console.warn('Participant not found in otherParticipants!', user.uid);
|
|
|
|
- this.markUserAsUnresolved(user, mediaType);
|
|
|
|
- }
|
|
|
|
- },
|
|
|
|
- // end: main flow
|
|
|
|
-
|
|
|
|
- // start: agora <-> WS sync helpers
|
|
|
|
- initUnrenderedParticipantsTimer: function () {
|
|
|
|
- this.unrenderedParticipantsTimer = window.setInterval(() => {
|
|
|
|
- this.unrenderedParticipants.forEach((_user) => {
|
|
|
|
- this.attemptToPlayParticipantMedia(_user, _user.mediaType);
|
|
|
|
- });
|
|
|
|
- }, 500);
|
|
|
|
- },
|
|
|
|
- initUnresolvedParticipantsTimer: function () {
|
|
|
|
- this.unresolvedParticipantsTimer = window.setInterval(() => {
|
|
|
|
- this.unresolvedParticipants.forEach((_user) => {
|
|
|
|
- this.attemptToPlayParticipantMedia(_user, _user.mediaType);
|
|
|
|
- });
|
|
|
|
- }, 1000);
|
|
|
|
- },
|
|
|
|
- markUserAsUnrendered: function (_user, _mediaType) {
|
|
|
|
- let existing = !!this.unrenderedParticipants.filter((_item) => _item.uid === _user.uid).length;
|
|
|
|
- if (!existing) {
|
|
|
|
- _user.mediaType = _mediaType;
|
|
|
|
- this.unrenderedParticipants.push(_user);
|
|
|
|
- }
|
|
|
|
- },
|
|
|
|
- markUserAsRendered: function (_user) {
|
|
|
|
- this.unrenderedParticipants = this.unrenderedParticipants.filter((_item) => _item.uid !== _user.uid);
|
|
|
|
- },
|
|
|
|
- markUserAsUnresolved: function (_user, _mediaType) {
|
|
|
|
- let existing = !!this.unresolvedParticipants.filter((_item) => _item.uid === _user.uid).length;
|
|
|
|
- if (!existing) {
|
|
|
|
- _user.mediaType = _mediaType;
|
|
|
|
- this.unresolvedParticipants.push(_user);
|
|
|
|
- }
|
|
|
|
- },
|
|
|
|
- markUserAsResolved: function (_user) {
|
|
|
|
- this.unresolvedParticipants = this.unresolvedParticipants.filter((_item) => _item.uid !== _user.uid);
|
|
|
|
- },
|
|
|
|
- // end: agora <-> WS sync helpers
|
|
|
|
-
|
|
|
|
- // start: actions that notify participants via socket
|
|
|
|
- myMicrophoneIsAcquired: function () {
|
|
|
|
- this.socketClient.send("/app/myMicrophoneIsAcquired", {},
|
|
|
|
- JSON.stringify({sessionKey: '{{$performer->session_key}}'})
|
|
|
|
- );
|
|
|
|
- },
|
|
|
|
- myMicrophoneIsNotAcquired: function () {
|
|
|
|
- this.socketClient.send("/app/myMicrophoneIsNotAcquired", {},
|
|
|
|
- JSON.stringify({sessionKey: '{{$performer->session_key}}'})
|
|
|
|
- );
|
|
|
|
- },
|
|
|
|
- myMicrophoneIsOn: function () {
|
|
|
|
- if (this.myMicrophone && this.myMedia.isMicrophoneAcquired) {
|
|
|
|
- this.myMedia.isMicrophoneOn = true;
|
|
|
|
- this.myMicrophone.setEnabled(true);
|
|
|
|
- this.socketClient.send("/app/myMicrophoneIsOn", {},
|
|
|
|
- JSON.stringify({sessionKey: '{{$performer->session_key}}'})
|
|
|
|
- );
|
|
|
|
- }
|
|
|
|
- },
|
|
|
|
- myMicrophoneIsOff: function () {
|
|
|
|
- if (this.myMicrophone) {
|
|
|
|
- this.myMicrophone.setEnabled(false);
|
|
|
|
- }
|
|
|
|
- this.myMedia.isMicrophoneOn = false;
|
|
|
|
- this.socketClient.send("/app/myMicrophoneIsOff", {},
|
|
|
|
- JSON.stringify({sessionKey: '{{$performer->session_key}}'})
|
|
|
|
- );
|
|
|
|
- },
|
|
|
|
- myCameraIsAcquired: function () {
|
|
|
|
- this.socketClient.send("/app/myCameraIsAcquired", {},
|
|
|
|
- JSON.stringify({sessionKey: '{{$performer->session_key}}'})
|
|
|
|
- );
|
|
|
|
- },
|
|
|
|
- myCameraIsNotAcquired: function () {
|
|
|
|
- this.socketClient.send("/app/myCameraIsNotAcquired", {},
|
|
|
|
- JSON.stringify({sessionKey: '{{$performer->session_key}}'})
|
|
|
|
- );
|
|
|
|
- },
|
|
|
|
- myCameraIsOn: function () {
|
|
|
|
- if (this.myCamera && this.myMedia.isCameraAcquired) {
|
|
|
|
- this.myCamera.setEnabled(true);
|
|
|
|
- this.myMedia.isCameraOn = true;
|
|
|
|
- this.socketClient.send("/app/myCameraIsOn", {},
|
|
|
|
- JSON.stringify({sessionKey: '{{$performer->session_key}}'})
|
|
|
|
- );
|
|
|
|
- }
|
|
|
|
- },
|
|
|
|
- myCameraIsOff: function () {
|
|
|
|
- if (this.myCamera) {
|
|
|
|
- this.myCamera.setEnabled(false);
|
|
|
|
- }
|
|
|
|
- this.myMedia.isCameraOn = false;
|
|
|
|
- this.socketClient.send("/app/myCameraIsOff", {},
|
|
|
|
- JSON.stringify({sessionKey: '{{$performer->session_key}}'})
|
|
|
|
- );
|
|
|
|
- },
|
|
|
|
- editMyName: function (_myNewName) {
|
|
|
|
- this.socketClient.send("/app/editMyName", {},
|
|
|
|
- JSON.stringify({
|
|
|
|
- sessionKey: '{{$performer->session_key}}',
|
|
|
|
- myNewName: _myNewName
|
|
|
|
- })
|
|
|
|
- );
|
|
|
|
- },
|
|
|
|
- setMyAwayMessage: function (_message) {
|
|
|
|
- this.socketClient.send("/app/setMyAwayMessage", {},
|
|
|
|
- JSON.stringify({
|
|
|
|
- sessionKey: '{{$performer->session_key}}',
|
|
|
|
- message: _message
|
|
|
|
- })
|
|
|
|
- );
|
|
|
|
- },
|
|
|
|
- removeMyAwayMessage: function () {
|
|
|
|
- this.socketClient.send("/app/removeMyAwayMessage", {},
|
|
|
|
- JSON.stringify({sessionKey: '{{$performer->session_key}}'})
|
|
|
|
- );
|
|
|
|
- },
|
|
|
|
- leaveClientRoom: function () {
|
|
|
|
- this.socketClient.send("/app/leaveClientRoom", {},
|
|
|
|
- JSON.stringify({sessionKey: '{{$performer->session_key}}'})
|
|
|
|
- );
|
|
|
|
- window.setTimeout(() => { // a little timeout for the WS message sending op to complete
|
|
|
|
- window.location.href = '/pro/meet';
|
|
|
|
- }, 250);
|
|
|
|
- },
|
|
|
|
- // end: actions that notify participants via socket
|
|
|
|
-
|
|
|
|
- // 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') {
|
|
|
|
- let videoContainer = $('[data-uid="' + this.myMediaServiceIdentifier + '"]');
|
|
|
|
- if (videoContainer.length) {
|
|
|
|
- track.play(videoContainer[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) {
|
|
|
|
- let videoContainer = $('[data-uid="' + remoteParticipant.uid + '"]');
|
|
|
|
- if (videoContainer.length) {
|
|
|
|
- remoteParticipant.videoTrack.play(videoContainer[0], {fit: 'contain'});
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- },
|
|
|
|
- // end: main view / thumb views
|
|
|
|
-
|
|
|
|
- // start: other/misc
|
|
|
|
- getMediaByMediaServiceId: function (_msid) {
|
|
|
|
- if ((+this.myMediaServiceIdentifier) === _msid) { // is it self?
|
|
|
|
- return this.myMedia;
|
|
|
|
- }
|
|
|
|
- for (let i = 0; i < this.otherParticipants.length; i++) { // or a remote participant
|
|
|
|
- if ((+this.otherParticipants[i].mediaServiceIdentifier) === _msid) {
|
|
|
|
- return this.otherParticipants[i].media;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- return { // return falsy object if nothing found
|
|
|
|
- isCameraAcquired: false,
|
|
|
|
- isCameraOn: false,
|
|
|
|
- isMicrophoneAcquired: false,
|
|
|
|
- isMicrophoneOn: false,
|
|
|
|
- };
|
|
|
|
- },
|
|
|
|
- toggleRinger: function () {
|
|
|
|
- $.post('/api/pro/' + (this.ringer ? 'turnOffRing' : 'turnOnRing'), (_data) => {
|
|
|
|
- if (!this.hasError(_data)) {
|
|
|
|
- this.ringer = !this.ringer;
|
|
|
|
- }
|
|
|
|
- }, 'json');
|
|
|
|
- },
|
|
|
|
- hasError: function (_data) { // check and report error if exists via toastr
|
|
|
|
- let msg = 'Unknown error!';
|
|
|
|
- if (_data) {
|
|
|
|
- if (_data.success) return false;
|
|
|
|
- else if (_data.message) msg = _data.message;
|
|
|
|
- }
|
|
|
|
- toastr.error(msg);
|
|
|
|
- return true;
|
|
|
|
- }
|
|
|
|
- // end: other/misc
|
|
|
|
- },
|
|
|
|
- mounted: function () {
|
|
|
|
- this.registerSocket();
|
|
|
|
- }
|
|
|
|
- });
|
|
|
|
- })();
|
|
|
|
-</script>
|
|
|
|
-
|
|
|
|
</body>
|
|
</body>
|
|
</html>
|
|
</html>
|