forked from sagi/seepur
Lots of fixes regarding call flow.
This commit is contained in:
parent
64bf37cf59
commit
0c355d549d
18 changed files with 203 additions and 177 deletions
|
@ -49,7 +49,7 @@ class CallSession {
|
|||
this.callId = callModel.id;
|
||||
this.callModel = callModel;
|
||||
this.callBooks = null;
|
||||
this.hostId = 2;
|
||||
this.hostId = callModel.guest_id;
|
||||
this.state = callModel.state;
|
||||
this.sessionState = {page: 'lobby', activity: {type: null, model: null}};
|
||||
this.parent = {
|
||||
|
@ -197,12 +197,14 @@ class CallSession {
|
|||
return !!this.parent.socket && !!this.guest.socket;
|
||||
}
|
||||
async onIceCandidate(payload) {
|
||||
if (!this.areAllPartnersConnected()) return true;
|
||||
const {peerId, userId, ice} = payload;
|
||||
this.userMap.get(peerId).socket.emit('wrtc:ice', {ice});
|
||||
console.log(`[Signal] [onIceCandidate] ${userId} -> ${peerId}`);
|
||||
return true;
|
||||
}
|
||||
async onSdpOffer(payload) {
|
||||
if (!this.areAllPartnersConnected()) return true;
|
||||
const {peerId, userId, sdp} = payload;
|
||||
this.userMap.get(peerId).socket.emit('wrtc:sdp:offer', {sdp});
|
||||
console.log(`[Signal] [onSdpOffer] ${userId} -> ${peerId}`);
|
||||
|
@ -210,6 +212,7 @@ class CallSession {
|
|||
}
|
||||
|
||||
async onSdpAnswer(payload) {
|
||||
if (!this.areAllPartnersConnected()) return true;
|
||||
const {peerId, userId, sdp} = payload;
|
||||
this.userMap.get(peerId).socket.emit('wrtc:sdp:answer', {sdp});
|
||||
console.log(`[Signal] [onSdpAnswer] ${userId} -> ${peerId}`);
|
||||
|
@ -217,6 +220,7 @@ class CallSession {
|
|||
}
|
||||
|
||||
onActionBookFlip(payload) {
|
||||
if (!this.areAllPartnersConnected()) return true;
|
||||
const {peerId, userId, direction} = payload;
|
||||
this.userMap.get(peerId).socket.emit('book:action:flip-page', {direction});
|
||||
console.log(`[Signal] [book] [action] [flip] [${direction}] ${userId} -> ${
|
||||
|
@ -224,6 +228,7 @@ class CallSession {
|
|||
return true;
|
||||
}
|
||||
onCallViewLobby(payload) {
|
||||
if (!this.areAllPartnersConnected()) return true;
|
||||
const {peerId, userId, direction} = payload;
|
||||
this.userMap.get(peerId).socket.emit('call:view:lobby', {});
|
||||
console.log(
|
||||
|
@ -232,6 +237,7 @@ class CallSession {
|
|||
}
|
||||
|
||||
onCallViewBook(payload) {
|
||||
if (!this.areAllPartnersConnected()) return true;
|
||||
const {peerId, userId, direction, bookId} = payload;
|
||||
this.userMap.get(peerId).socket.emit('call:view:book', {bookId});
|
||||
console.log(
|
||||
|
@ -245,11 +251,9 @@ class CallSession {
|
|||
console.log('Host: ', this.hostId);
|
||||
this.userMap.get(userId).socket.emit(
|
||||
'call:host:changed', {hostId: this.hostId});
|
||||
try {
|
||||
if (this.userMap.get(peerId) && this.userMap.get(peerId).socket)
|
||||
this.userMap.get(peerId).socket.emit(
|
||||
'call:host:changed', {hostId: this.hostId});
|
||||
} catch (e) {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -30,7 +30,7 @@ import Notification from "../shared/components/Notification.vue";
|
|||
import { mapActions, mapGetters } from "vuex";
|
||||
import Loading from "../shared/components/Loading/Loading.vue";
|
||||
import TopNavbar from "../shared/components/TopNavbar.vue";
|
||||
import WebsocketService from "./scripts/websocket.service";
|
||||
import WebsocketService from "./ws/websocket.service";
|
||||
// import AppRouter from "./router/router.vue";
|
||||
|
||||
// Services.ApiService.getConnections();
|
||||
|
@ -45,7 +45,8 @@ export default {
|
|||
TopNavbar
|
||||
},
|
||||
async created() {
|
||||
await this.getUser();
|
||||
const u = await this.getUser();
|
||||
// console.log(u);
|
||||
this.ws = await WebsocketService.getInstance();
|
||||
this.ws.on(WebsocketService.Events.CONNECTION_ONLINE, user => {
|
||||
console.log(`User Online: ${JSON.stringify(user, null, 2)}`);
|
||||
|
|
|
@ -395,7 +395,8 @@ var script = {
|
|||
this.onResize();
|
||||
this.preloadImages();
|
||||
this.zoom = this.zooms_[0];
|
||||
return this.goToPage(this.startPage);
|
||||
this.goToPage(this.startPage);
|
||||
return this.$emit('on-mounted', this);
|
||||
},
|
||||
beforeDestroy: function() {
|
||||
return window.removeEventListener('resize', this.onResize, {
|
||||
|
@ -797,19 +798,7 @@ var script = {
|
|||
return this.zoomTo(this.zooms_[this.zoomIndex], x, y);
|
||||
},
|
||||
swipeStart: function(touch) {
|
||||
if (!this.enabled) {
|
||||
return;
|
||||
}
|
||||
this.touchStartX = touch.pageX;
|
||||
this.touchStartY = touch.pageY;
|
||||
this.maxMove = 0;
|
||||
if (this.zoom <= 1) {
|
||||
return this.activeCursor = 'grab';
|
||||
} else {
|
||||
this.startScrollLeft = this.$refs.viewport.scrollLeft;
|
||||
this.startScrollTop = this.$refs.viewport.scrollTop;
|
||||
return this.activeCursor = 'all-scroll';
|
||||
}
|
||||
return;
|
||||
},
|
||||
swipeMove: function(touch) {
|
||||
var x, y;
|
||||
|
@ -1244,11 +1233,11 @@ var __vue_staticRenderFns__ = [];
|
|||
/* style */
|
||||
var __vue_inject_styles__ = function (inject) {
|
||||
if (!inject) { return }
|
||||
inject("data-v-16acf8ed_0", { source: ".viewport[data-v-16acf8ed]{-webkit-overflow-scrolling:touch;width:100%;height:95%}.viewport.zoom[data-v-16acf8ed]{overflow:scroll}.viewport.zoom.drag-to-scroll[data-v-16acf8ed]{overflow:hidden}.book-container[data-v-16acf8ed]{position:relative;width:100%;height:95%;transform-origin:top left;-webkit-user-select:none;-ms-user-select:none;user-select:none}.click-to-flip[data-v-16acf8ed]{position:absolute;width:50%;height:100%;top:0;-webkit-user-select:none;-ms-user-select:none;user-select:none}.click-to-flip.left[data-v-16acf8ed]{left:0}.click-to-flip.right[data-v-16acf8ed]{right:0}.bounding-box[data-v-16acf8ed]{position:absolute;-webkit-user-select:none;-ms-user-select:none;user-select:none}.page[data-v-16acf8ed]{position:absolute;-webkit-backface-visibility:hidden;backface-visibility:hidden}.polygon[data-v-16acf8ed]{position:absolute;top:0;left:0;background-repeat:no-repeat;-webkit-backface-visibility:hidden;backface-visibility:hidden;transform-origin:center left}.polygon.blank[data-v-16acf8ed]{background-color:#ddd}.polygon .lighting[data-v-16acf8ed]{width:100%;height:100%}", map: undefined, media: undefined });
|
||||
inject("data-v-77b9888e_0", { source: ".viewport[data-v-77b9888e]{-webkit-overflow-scrolling:touch;width:100%;height:95%}.viewport.zoom[data-v-77b9888e]{overflow:scroll}.viewport.zoom.drag-to-scroll[data-v-77b9888e]{overflow:hidden}.book-container[data-v-77b9888e]{position:relative;width:100%;height:95%;transform-origin:top left;-webkit-user-select:none;-ms-user-select:none;user-select:none}.click-to-flip[data-v-77b9888e]{position:absolute;width:50%;height:100%;top:0;-webkit-user-select:none;-ms-user-select:none;user-select:none}.click-to-flip.left[data-v-77b9888e]{left:0}.click-to-flip.right[data-v-77b9888e]{right:0}.bounding-box[data-v-77b9888e]{position:absolute;-webkit-user-select:none;-ms-user-select:none;user-select:none}.page[data-v-77b9888e]{position:absolute;-webkit-backface-visibility:hidden;backface-visibility:hidden;box-shadow:0 0 15px -4px rgba(0,0,0,.75)}.polygon[data-v-77b9888e]{position:absolute;top:0;left:0;background-repeat:no-repeat;-webkit-backface-visibility:hidden;backface-visibility:hidden;transform-origin:center left}.polygon.blank[data-v-77b9888e]{background-color:#ddd}.polygon .lighting[data-v-77b9888e]{width:100%;height:100%}", map: undefined, media: undefined });
|
||||
|
||||
};
|
||||
/* scoped */
|
||||
var __vue_scope_id__ = "data-v-16acf8ed";
|
||||
var __vue_scope_id__ = "data-v-77b9888e";
|
||||
/* module identifier */
|
||||
var __vue_module_identifier__ = undefined;
|
||||
/* functional template */
|
||||
|
|
|
@ -393,7 +393,8 @@ var script = {
|
|||
this.onResize();
|
||||
this.preloadImages();
|
||||
this.zoom = this.zooms_[0];
|
||||
return this.goToPage(this.startPage);
|
||||
this.goToPage(this.startPage);
|
||||
return this.$emit('on-mounted', this);
|
||||
},
|
||||
beforeDestroy: function() {
|
||||
return window.removeEventListener('resize', this.onResize, {
|
||||
|
@ -795,19 +796,7 @@ var script = {
|
|||
return this.zoomTo(this.zooms_[this.zoomIndex], x, y);
|
||||
},
|
||||
swipeStart: function(touch) {
|
||||
if (!this.enabled) {
|
||||
return;
|
||||
}
|
||||
this.touchStartX = touch.pageX;
|
||||
this.touchStartY = touch.pageY;
|
||||
this.maxMove = 0;
|
||||
if (this.zoom <= 1) {
|
||||
return this.activeCursor = 'grab';
|
||||
} else {
|
||||
this.startScrollLeft = this.$refs.viewport.scrollLeft;
|
||||
this.startScrollTop = this.$refs.viewport.scrollTop;
|
||||
return this.activeCursor = 'all-scroll';
|
||||
}
|
||||
return;
|
||||
},
|
||||
swipeMove: function(touch) {
|
||||
var x, y;
|
||||
|
@ -1242,11 +1231,11 @@ var __vue_staticRenderFns__ = [];
|
|||
/* style */
|
||||
var __vue_inject_styles__ = function (inject) {
|
||||
if (!inject) { return }
|
||||
inject("data-v-16acf8ed_0", { source: ".viewport[data-v-16acf8ed]{-webkit-overflow-scrolling:touch;width:100%;height:95%}.viewport.zoom[data-v-16acf8ed]{overflow:scroll}.viewport.zoom.drag-to-scroll[data-v-16acf8ed]{overflow:hidden}.book-container[data-v-16acf8ed]{position:relative;width:100%;height:95%;transform-origin:top left;-webkit-user-select:none;-ms-user-select:none;user-select:none}.click-to-flip[data-v-16acf8ed]{position:absolute;width:50%;height:100%;top:0;-webkit-user-select:none;-ms-user-select:none;user-select:none}.click-to-flip.left[data-v-16acf8ed]{left:0}.click-to-flip.right[data-v-16acf8ed]{right:0}.bounding-box[data-v-16acf8ed]{position:absolute;-webkit-user-select:none;-ms-user-select:none;user-select:none}.page[data-v-16acf8ed]{position:absolute;-webkit-backface-visibility:hidden;backface-visibility:hidden}.polygon[data-v-16acf8ed]{position:absolute;top:0;left:0;background-repeat:no-repeat;-webkit-backface-visibility:hidden;backface-visibility:hidden;transform-origin:center left}.polygon.blank[data-v-16acf8ed]{background-color:#ddd}.polygon .lighting[data-v-16acf8ed]{width:100%;height:100%}", map: undefined, media: undefined });
|
||||
inject("data-v-77b9888e_0", { source: ".viewport[data-v-77b9888e]{-webkit-overflow-scrolling:touch;width:100%;height:95%}.viewport.zoom[data-v-77b9888e]{overflow:scroll}.viewport.zoom.drag-to-scroll[data-v-77b9888e]{overflow:hidden}.book-container[data-v-77b9888e]{position:relative;width:100%;height:95%;transform-origin:top left;-webkit-user-select:none;-ms-user-select:none;user-select:none}.click-to-flip[data-v-77b9888e]{position:absolute;width:50%;height:100%;top:0;-webkit-user-select:none;-ms-user-select:none;user-select:none}.click-to-flip.left[data-v-77b9888e]{left:0}.click-to-flip.right[data-v-77b9888e]{right:0}.bounding-box[data-v-77b9888e]{position:absolute;-webkit-user-select:none;-ms-user-select:none;user-select:none}.page[data-v-77b9888e]{position:absolute;-webkit-backface-visibility:hidden;backface-visibility:hidden;box-shadow:0 0 15px -4px rgba(0,0,0,.75)}.polygon[data-v-77b9888e]{position:absolute;top:0;left:0;background-repeat:no-repeat;-webkit-backface-visibility:hidden;backface-visibility:hidden;transform-origin:center left}.polygon.blank[data-v-77b9888e]{background-color:#ddd}.polygon .lighting[data-v-77b9888e]{width:100%;height:100%}", map: undefined, media: undefined });
|
||||
|
||||
};
|
||||
/* scoped */
|
||||
var __vue_scope_id__ = "data-v-16acf8ed";
|
||||
var __vue_scope_id__ = "data-v-77b9888e";
|
||||
/* module identifier */
|
||||
var __vue_module_identifier__ = undefined;
|
||||
/* functional template */
|
||||
|
|
|
@ -576,7 +576,8 @@
|
|||
this.onResize();
|
||||
this.preloadImages();
|
||||
this.zoom = this.zooms_[0];
|
||||
return this.goToPage(this.startPage);
|
||||
this.goToPage(this.startPage);
|
||||
return this.$emit('on-mounted', this);
|
||||
},
|
||||
beforeDestroy: function() {
|
||||
return window.removeEventListener('resize', this.onResize, {
|
||||
|
@ -978,19 +979,7 @@
|
|||
return this.zoomTo(this.zooms_[this.zoomIndex], x, y);
|
||||
},
|
||||
swipeStart: function(touch) {
|
||||
if (!this.enabled) {
|
||||
return;
|
||||
}
|
||||
this.touchStartX = touch.pageX;
|
||||
this.touchStartY = touch.pageY;
|
||||
this.maxMove = 0;
|
||||
if (this.zoom <= 1) {
|
||||
return this.activeCursor = 'grab';
|
||||
} else {
|
||||
this.startScrollLeft = this.$refs.viewport.scrollLeft;
|
||||
this.startScrollTop = this.$refs.viewport.scrollTop;
|
||||
return this.activeCursor = 'all-scroll';
|
||||
}
|
||||
return;
|
||||
},
|
||||
swipeMove: function(touch) {
|
||||
var x, y;
|
||||
|
@ -1425,11 +1414,11 @@
|
|||
/* style */
|
||||
var __vue_inject_styles__ = function (inject) {
|
||||
if (!inject) { return }
|
||||
inject("data-v-16acf8ed_0", { source: ".viewport[data-v-16acf8ed]{-webkit-overflow-scrolling:touch;width:100%;height:95%}.viewport.zoom[data-v-16acf8ed]{overflow:scroll}.viewport.zoom.drag-to-scroll[data-v-16acf8ed]{overflow:hidden}.book-container[data-v-16acf8ed]{position:relative;width:100%;height:95%;transform-origin:top left;-webkit-user-select:none;-ms-user-select:none;user-select:none}.click-to-flip[data-v-16acf8ed]{position:absolute;width:50%;height:100%;top:0;-webkit-user-select:none;-ms-user-select:none;user-select:none}.click-to-flip.left[data-v-16acf8ed]{left:0}.click-to-flip.right[data-v-16acf8ed]{right:0}.bounding-box[data-v-16acf8ed]{position:absolute;-webkit-user-select:none;-ms-user-select:none;user-select:none}.page[data-v-16acf8ed]{position:absolute;-webkit-backface-visibility:hidden;backface-visibility:hidden}.polygon[data-v-16acf8ed]{position:absolute;top:0;left:0;background-repeat:no-repeat;-webkit-backface-visibility:hidden;backface-visibility:hidden;transform-origin:center left}.polygon.blank[data-v-16acf8ed]{background-color:#ddd}.polygon .lighting[data-v-16acf8ed]{width:100%;height:100%}", map: undefined, media: undefined });
|
||||
inject("data-v-77b9888e_0", { source: ".viewport[data-v-77b9888e]{-webkit-overflow-scrolling:touch;width:100%;height:95%}.viewport.zoom[data-v-77b9888e]{overflow:scroll}.viewport.zoom.drag-to-scroll[data-v-77b9888e]{overflow:hidden}.book-container[data-v-77b9888e]{position:relative;width:100%;height:95%;transform-origin:top left;-webkit-user-select:none;-ms-user-select:none;user-select:none}.click-to-flip[data-v-77b9888e]{position:absolute;width:50%;height:100%;top:0;-webkit-user-select:none;-ms-user-select:none;user-select:none}.click-to-flip.left[data-v-77b9888e]{left:0}.click-to-flip.right[data-v-77b9888e]{right:0}.bounding-box[data-v-77b9888e]{position:absolute;-webkit-user-select:none;-ms-user-select:none;user-select:none}.page[data-v-77b9888e]{position:absolute;-webkit-backface-visibility:hidden;backface-visibility:hidden;box-shadow:0 0 15px -4px rgba(0,0,0,.75)}.polygon[data-v-77b9888e]{position:absolute;top:0;left:0;background-repeat:no-repeat;-webkit-backface-visibility:hidden;backface-visibility:hidden;transform-origin:center left}.polygon.blank[data-v-77b9888e]{background-color:#ddd}.polygon .lighting[data-v-77b9888e]{width:100%;height:100%}", map: undefined, media: undefined });
|
||||
|
||||
};
|
||||
/* scoped */
|
||||
var __vue_scope_id__ = "data-v-16acf8ed";
|
||||
var __vue_scope_id__ = "data-v-77b9888e";
|
||||
/* module identifier */
|
||||
var __vue_module_identifier__ = undefined;
|
||||
/* functional template */
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1,15 +1,12 @@
|
|||
import Vue from 'vue';
|
||||
import Vuex, { Store } from "vuex";
|
||||
import Services from '../services';
|
||||
import CallManager, { ECallEvents } from "./classes/call.manager";
|
||||
import WebsocketService from './scripts/websocket.service';
|
||||
import { createContext } from 'vm';
|
||||
|
||||
Vue.use(Vuex);
|
||||
const store = new Store({
|
||||
strict: true,
|
||||
state: {
|
||||
inCall: false,
|
||||
callManager: null as CallManager,
|
||||
user: { name: 'loading...', is_admin: false, id: null, books: [] },
|
||||
notifications: []
|
||||
},
|
||||
|
@ -20,9 +17,6 @@ const store = new Store({
|
|||
notifications(state) {
|
||||
return state.notifications;
|
||||
},
|
||||
callManager(state): CallManager {
|
||||
return state.callManager;
|
||||
},
|
||||
inCall(state) {
|
||||
return state.inCall;
|
||||
}
|
||||
|
@ -43,11 +37,9 @@ const store = new Store({
|
|||
state.notifications = state.notifications.filter(n => n.id != noteId);
|
||||
},
|
||||
callEnded(state) {
|
||||
state.callManager = null;
|
||||
state.inCall = false;
|
||||
},
|
||||
connectToCall(state, options: { callId: number, ws: any }) {
|
||||
state.callManager = new CallManager(options.ws, options.callId, state.user.id);
|
||||
callStarted(state) {
|
||||
state.inCall = true;
|
||||
}
|
||||
},
|
||||
|
@ -55,6 +47,7 @@ const store = new Store({
|
|||
async getUser(ctx, userId?: number) {
|
||||
const user = await Services.ApiService.getUser(userId);
|
||||
ctx.commit('setUser', user);
|
||||
return user;
|
||||
},
|
||||
notify(ctx, notification: { message: string, level?: "info" | "warning" | "success" | "danger" }) {
|
||||
ctx.commit("notify", notification);
|
||||
|
@ -65,13 +58,8 @@ const store = new Store({
|
|||
callEnded(ctx) {
|
||||
ctx.commit('callEnded');
|
||||
},
|
||||
async connectToCall(ctx, callId: string) {
|
||||
if (!ctx.state.inCall) {
|
||||
const ws = await WebsocketService.getInstance();
|
||||
ctx.commit('connectToCall', { callId, ws });
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
callStarted(ctx) {
|
||||
ctx.commit('callStarted');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -12,7 +12,8 @@
|
|||
|
||||
<script lang="ts">
|
||||
import Loading from "../../shared/components/Loading/Loading.vue";
|
||||
import { ECallEvents } from "../classes/call.manager";
|
||||
import CallManager, { ECallEvents } from "../ws/call.manager";
|
||||
import WebsocketService from "../ws/websocket.service";
|
||||
import VideoStrip from "./call_views/VideoStrip.vue";
|
||||
import Services from "../../services/index";
|
||||
import { mapActions, mapGetters } from "vuex";
|
||||
|
@ -22,25 +23,22 @@ export default {
|
|||
VideoStrip
|
||||
},
|
||||
name: "Call",
|
||||
// mounted() {
|
||||
// const self = this;
|
||||
// setTimeout(() => {
|
||||
// self.isMounted = true;
|
||||
// }, 1000);
|
||||
// },
|
||||
async created() {
|
||||
this.loading = true;
|
||||
try {
|
||||
const callId = Number(this.$route.params.id);
|
||||
const ws = await WebsocketService.getInstance();
|
||||
this.callManager = ws.callManager;
|
||||
this.callManager.on(ECallEvents.CLOSE, this.endCall);
|
||||
|
||||
await this.connectToCall(callId);
|
||||
|
||||
this.callManager.on(ECallEvents.CLOSE, this.callEnded);
|
||||
|
||||
const success = await this.callManager.connectToCall({
|
||||
video: true,
|
||||
audio: true
|
||||
});
|
||||
const success = await this.callManager.connectToCall(
|
||||
this.user.id,
|
||||
{
|
||||
video: true,
|
||||
audio: true
|
||||
},
|
||||
callId
|
||||
);
|
||||
this.callManager.on(
|
||||
ECallEvents.CALL_HOST_CHANGED,
|
||||
this.onRemoteHostChanged
|
||||
|
@ -50,6 +48,7 @@ export default {
|
|||
this.$router.push({ path: `/` });
|
||||
return false;
|
||||
}
|
||||
this.callStarted();
|
||||
this.localStream = await this.callManager.getUserMedia();
|
||||
this.remoteStream = this.callManager.getRemoteStream();
|
||||
this.notify({ message: "Connected!", level: "success" });
|
||||
|
@ -63,14 +62,14 @@ export default {
|
|||
async beforeDestroy() {
|
||||
console.log("destroyed");
|
||||
this.callManager.close();
|
||||
this.$store.dispatch("callEnded");
|
||||
this.callEnded();
|
||||
return true;
|
||||
},
|
||||
methods: {
|
||||
async setupCall(): Promise<boolean> {
|
||||
return true;
|
||||
},
|
||||
callEnded(callId) {
|
||||
endCall(callId) {
|
||||
this.notify({ message: `Call #${callId} Ended` });
|
||||
this.$router.replace({ path: `/` });
|
||||
},
|
||||
|
@ -82,19 +81,17 @@ export default {
|
|||
changeHost() {
|
||||
this.callManager.changeHost();
|
||||
},
|
||||
...mapActions(["notify", "connectToCall"])
|
||||
...mapActions(["notify", "callStarted", "callEnded"])
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(["user", "callManager", "inCall"])
|
||||
...mapGetters(["user", "inCall"])
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loading: true,
|
||||
localStream: null,
|
||||
remoteStream: null
|
||||
// currentPage: 0,
|
||||
// totalPages: 34,
|
||||
// isMounted: false
|
||||
remoteStream: null,
|
||||
callManager: null as CallManager
|
||||
};
|
||||
},
|
||||
beforeCreate: () => {}
|
||||
|
|
|
@ -1,45 +1,43 @@
|
|||
<template>
|
||||
<div class="book-view">
|
||||
<!-- <nav class="level">
|
||||
<div class="level-left">
|
||||
<div class="level-item">
|
||||
<button class="button" @click="$router.back()">Back</button>
|
||||
<div>
|
||||
<Loading v-if="loading" />
|
||||
|
||||
<div class="book-view" v-else>
|
||||
<div class="is-flex">
|
||||
<div class="go-left m-r-sm" style="display: flex; align-items: center;">
|
||||
<button
|
||||
class="button book-flip-buttons"
|
||||
:disabled="!(callManager.isHost && canFlipLeft)"
|
||||
@click="onLeftClicked()"
|
||||
>
|
||||
<i class="fa fa-fw fa-arrow-left"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</nav>-->
|
||||
<div class="is-flex">
|
||||
<div class="go-left m-r-sm" style="display: flex; align-items: center;">
|
||||
<button
|
||||
class="button book-flip-buttons"
|
||||
:disabled="!callManager.isHost"
|
||||
@click="onLeftClicked()"
|
||||
<flipbook
|
||||
class="flipbook"
|
||||
:pages="createPages"
|
||||
:forwardDirection="callManager.currentActivity.ltr ? 'right': 'left'"
|
||||
:zooms="null"
|
||||
:enabled="callManager.isHost"
|
||||
@on-mounted="bookMounted()"
|
||||
ref="flipbook"
|
||||
v-slot="flipbook"
|
||||
>
|
||||
<i class="fa fa-fw fa-arrow-left"></i>
|
||||
</button>
|
||||
</div>
|
||||
<flipbook
|
||||
class="flipbook"
|
||||
:pages="createPages(callManager.currentActivity)"
|
||||
:forwardDirection="callManager.currentActivity.ltr ? 'right': 'left'"
|
||||
:zooms="null"
|
||||
:enabled="callManager.isHost"
|
||||
@flip-left-end="onFlip('left')"
|
||||
@flip-right-end="onFlip('right')"
|
||||
ref="flipbook"
|
||||
v-slot="flipbook"
|
||||
>
|
||||
<div class="page-progress has-text-centered m-b-none">
|
||||
<p>Page {{ flipbook.page }} of {{ flipbook.numPages }}</p>
|
||||
<!-- @flip-left-start="onFlip('left')" -->
|
||||
<!-- @flip-right-start="onFlip('right')" -->
|
||||
<div class="page-progress has-text-centered m-b-none">
|
||||
<p>Page {{ flipbook.page }} of {{ flipbook.numPages }}</p>
|
||||
</div>
|
||||
</flipbook>
|
||||
<div class="go-right m-l-sm" style="display: flex; align-items: center;">
|
||||
<button
|
||||
class="button book-flip-buttons"
|
||||
:disabled="!(callManager.isHost && canFlipRight)"
|
||||
@click="onRightClicked()"
|
||||
>
|
||||
<i class="fa fa-fw fa-arrow-right"></i>
|
||||
</button>
|
||||
</div>
|
||||
</flipbook>
|
||||
<div class="go-right m-l-sm" style="display: flex; align-items: center;">
|
||||
<button
|
||||
class="button book-flip-buttons"
|
||||
:disabled="!callManager.isHost"
|
||||
@click="onRightClicked()"
|
||||
>
|
||||
<i class="fa fa-fw fa-arrow-right"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -47,38 +45,76 @@
|
|||
|
||||
<script lang="ts">
|
||||
import Flipbook from "../../components/flipbook/flipbook.cjs.js";
|
||||
import { ECallEvents } from "../../classes/call.manager";
|
||||
import Loading from "../../../shared/components/Loading/Loading.vue";
|
||||
import CallManager, { ECallEvents } from "../../ws/call.manager";
|
||||
import WebsocketService from "../../ws/websocket.service";
|
||||
import { mapActions, mapGetters } from "vuex";
|
||||
export default {
|
||||
name: "CallBook",
|
||||
components: { Flipbook },
|
||||
created() {
|
||||
components: { Flipbook, Loading },
|
||||
async created() {
|
||||
const ws = await WebsocketService.getInstance();
|
||||
this.callManager = ws.callManager;
|
||||
this.callManager.on(
|
||||
ECallEvents.ACTION_BOOK_FLIP,
|
||||
this.onRemoteFlip.bind(this)
|
||||
);
|
||||
this.loading = false;
|
||||
return true;
|
||||
},
|
||||
destroyed() {
|
||||
this.callManager.removeListener(
|
||||
ECallEvents.ACTION_BOOK_FLIP,
|
||||
this.onRemoteFlip.bind(this)
|
||||
);
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loading: true,
|
||||
localStream: null,
|
||||
remoteStream: null
|
||||
remoteStream: null,
|
||||
flipbookRef: false,
|
||||
callManager: { isHost: false } as CallManager
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(["user", "callManager"])
|
||||
canFlipLeft() {
|
||||
return this.flipbookRef && this.$refs.flipbook.canFlipLeft;
|
||||
},
|
||||
canFlipRight() {
|
||||
return this.flipbookRef && this.$refs.flipbook.canFlipRight;
|
||||
},
|
||||
createPages() {
|
||||
const pages = [null];
|
||||
for (let i = 1; i < this.callManager.currentActivity.pages + 1; i++) {
|
||||
pages.push(
|
||||
`/u/call/${this.callManager.callId}/books/${this.callManager.currentActivity.id}/page/${i}`
|
||||
);
|
||||
}
|
||||
return pages;
|
||||
},
|
||||
...mapGetters(["user"])
|
||||
},
|
||||
methods: {
|
||||
onFlip(direction: "left" | "right") {
|
||||
if (this.callManager.isHost)
|
||||
this.callManager.send(`book:action:flip-page`, { direction });
|
||||
bookMounted() {
|
||||
console.log("Book Mounted!");
|
||||
if (this.$refs.flipbook) {
|
||||
console.log("Found!");
|
||||
this.flipbookRef = true;
|
||||
} else {
|
||||
console.log("Still Null!!");
|
||||
}
|
||||
},
|
||||
onLeftClicked() {
|
||||
this.callManager.send(`book:action:flip-page`, { direction: "left" });
|
||||
this.$refs.flipbook.flipLeft();
|
||||
},
|
||||
onRightClicked() {
|
||||
this.callManager.send(`book:action:flip-page`, { direction: "right" });
|
||||
this.$refs.flipbook.flipRight();
|
||||
},
|
||||
onRemoteFlip(payload) {
|
||||
console.log("remote Flip!");
|
||||
switch (payload.direction) {
|
||||
case "left":
|
||||
this.$refs.flipbook.flipLeft();
|
||||
|
@ -87,15 +123,6 @@ export default {
|
|||
this.$refs.flipbook.flipRight();
|
||||
break;
|
||||
}
|
||||
},
|
||||
createPages(book) {
|
||||
const pages = [null];
|
||||
for (let i = 1; i < book.pages + 1; i++) {
|
||||
pages.push(
|
||||
`/u/call/${this.callManager.callId}/books/${book.id}/page/${i}`
|
||||
);
|
||||
}
|
||||
return pages;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -28,15 +28,23 @@
|
|||
|
||||
<script lang="ts">
|
||||
import { mapGetters } from "vuex";
|
||||
import { ECallEvents } from "../../classes/call.manager";
|
||||
import { ECallEvents } from "../../ws/call.manager";
|
||||
import WebsocketService from "../../ws/websocket.service";
|
||||
export default {
|
||||
name: "CallLobby",
|
||||
created() {
|
||||
async created() {
|
||||
const ws = await WebsocketService.getInstance();
|
||||
this.callManager = ws.callManager;
|
||||
this.callManager.on(
|
||||
ECallEvents.CALL_VIEW_BOOK,
|
||||
this.remoteBookSelected.bind(this)
|
||||
);
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
callManager: { books: [] }
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
goToBook(book, index, remote) {
|
||||
if (remote || this.callManager.isHost) {
|
||||
|
@ -55,7 +63,7 @@ export default {
|
|||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(["callManager"])
|
||||
...mapGetters(["user"])
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
import WebSocketService from "../scripts/websocket.service";
|
||||
import WebSocketService from "./websocket.service";
|
||||
import { EventEmitter } from "events";
|
||||
|
||||
|
||||
let singleton: CallManager = null;
|
||||
|
||||
export default class CallManager {
|
||||
private inCall: boolean;
|
||||
public peerId: number;
|
||||
|
@ -13,7 +17,9 @@ export default class CallManager {
|
|||
public isHost = false;
|
||||
public books = [];
|
||||
public currentActivity = null;
|
||||
constructor(private ws: WebSocketService, readonly callId: number, private userId: number) {
|
||||
public callId;
|
||||
private userId: number
|
||||
constructor(private ws: WebSocketService) {
|
||||
this.inCall = false;
|
||||
this.peerId = null;
|
||||
this.pc = null;
|
||||
|
@ -21,8 +27,10 @@ export default class CallManager {
|
|||
}
|
||||
|
||||
|
||||
async connectToCall(mediaConstraints: MediaStreamConstraints): Promise<boolean> {
|
||||
async connectToCall(userId: number, mediaConstraints: MediaStreamConstraints, callId: number): Promise<boolean> {
|
||||
if (this.inCall) throw new Error('Already connected to call');
|
||||
this.callId = callId;
|
||||
this.userId = userId;
|
||||
console.log('connecting to call');
|
||||
await this.getUserMedia(mediaConstraints);
|
||||
this.signalingChannel = this.ws.subscribe(`call:${this.callId}`);
|
||||
|
@ -53,6 +61,9 @@ export default class CallManager {
|
|||
on(event: ECallEvents, callback: (...args) => void) {
|
||||
this.emitter.on(event, callback);
|
||||
}
|
||||
removeListener(event: ECallEvents, callback: (...args) => void) {
|
||||
this.emitter.removeListener(event, callback);
|
||||
}
|
||||
private emit(event: ECallEvents, data: any) {
|
||||
this.emitter.emit(event, data);
|
||||
}
|
||||
|
@ -69,7 +80,7 @@ export default class CallManager {
|
|||
console.log(payload);
|
||||
this.peerId = payload.peerId;
|
||||
this.books = payload.books;
|
||||
this.isHost = this.peerId === payload.hostId;
|
||||
this.isHost = this.userId === payload.hostId;
|
||||
this.pc = new RTCPeerConnection({ iceServers: payload.iceServers });
|
||||
this.child = payload.child;
|
||||
payload.users.forEach(u => {
|
||||
|
@ -94,7 +105,7 @@ export default class CallManager {
|
|||
console.log(payload);
|
||||
this.peerId = payload.peerId;
|
||||
this.books = payload.books;
|
||||
this.isHost = this.peerId === payload.hostId;
|
||||
this.isHost = this.userId === payload.hostId;
|
||||
this.pc = new RTCPeerConnection({ iceServers: payload.iceServers });
|
||||
this.child = payload.child;
|
||||
payload.users.forEach(u => {
|
||||
|
@ -115,6 +126,7 @@ export default class CallManager {
|
|||
}
|
||||
public backToLobby() {
|
||||
console.log('-------> backToLobby');
|
||||
this.emitter.removeAllListeners(ECallEvents.ACTION_BOOK_FLIP);
|
||||
this.send('call:view:lobby', {});
|
||||
}
|
||||
|
||||
|
@ -194,11 +206,12 @@ export default class CallManager {
|
|||
}
|
||||
|
||||
onRemoteHostChanged(payload) {
|
||||
this.isHost = this.peerId === payload.hostId;
|
||||
this.isHost = this.userId === payload.hostId;
|
||||
this.emit(ECallEvents.CALL_HOST_CHANGED, payload);
|
||||
}
|
||||
|
||||
onRemoteViewLobby(payload) {
|
||||
this.emitter.removeAllListeners(ECallEvents.ACTION_BOOK_FLIP);
|
||||
this.emit(ECallEvents.CALL_VIEW_LOBBY, null);
|
||||
}
|
||||
onRemoteViewBook(payload) {
|
||||
|
@ -215,7 +228,9 @@ export default class CallManager {
|
|||
if (this.localStream) this.localStream.getTracks().forEach(t => t.stop());
|
||||
this.localStream = null;
|
||||
this.remoteStream = null;
|
||||
this.emitter.removeAllListeners();
|
||||
this.inCall = false;
|
||||
singleton = null;
|
||||
}
|
||||
|
||||
}
|
|
@ -26,7 +26,8 @@ export default class UserChannel {
|
|||
|
||||
static async getInstance(ws) {
|
||||
if (singleton) return singleton;
|
||||
else return new UserChannel(ws);
|
||||
singleton = new UserChannel(ws);
|
||||
return singleton;
|
||||
}
|
||||
close() {
|
||||
this.subscription.close();
|
|
@ -2,6 +2,7 @@
|
|||
import Ws from "@adonisjs/websocket-client";
|
||||
import UserChannelService from './user.channel.service';
|
||||
import { EventEmitter } from 'events';
|
||||
import CallManager from "./call.manager";
|
||||
let singleton: WebSocketService = null;
|
||||
enum EEvents {
|
||||
NEW_CONNECTION,
|
||||
|
@ -12,6 +13,7 @@ enum EEvents {
|
|||
export default class WebSocketService {
|
||||
static Events = EEvents;
|
||||
private emitter;
|
||||
readonly callManager: CallManager;
|
||||
|
||||
private constructor(private ws, private userChannelService: UserChannelService) {
|
||||
this.emitter = new EventEmitter();
|
||||
|
@ -19,6 +21,7 @@ export default class WebSocketService {
|
|||
this.userChannelService.on('connection:online', this.onUserConnectionOnline.bind(this));
|
||||
this.userChannelService.on('connection:offline', this.onUserConnectionOffline.bind(this));
|
||||
this.userChannelService.on('call:incoming', this.onIncomingCall.bind(this));
|
||||
this.callManager = new CallManager(this);
|
||||
}
|
||||
|
||||
|
|
@ -89,28 +89,43 @@
|
|||
|
||||
<script lang="ts">
|
||||
import { mapGetters, mapActions } from "vuex";
|
||||
import { ECallEvents } from "../../home/classes/call.manager";
|
||||
import CallManager, { ECallEvents } from "../../home/ws/call.manager";
|
||||
import WebsocketService from "../../home/ws/websocket.service";
|
||||
export default {
|
||||
name: "TobNavbar",
|
||||
created() {},
|
||||
async created() {
|
||||
const ws = await WebsocketService.getInstance();
|
||||
this.callManager = ws.callManager;
|
||||
},
|
||||
updated() {
|
||||
if (!this.inCall) {
|
||||
this.subscribedToLobbyEvents = false;
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
showMenu: false
|
||||
showMenu: false,
|
||||
subscribedToLobbyEvents: false,
|
||||
callManager: null as CallManager
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
host() {
|
||||
if (this.inCall) {
|
||||
this.callManager.on(
|
||||
ECallEvents.CALL_VIEW_LOBBY,
|
||||
this.remoteBackToLobby.bind(this)
|
||||
);
|
||||
if (!this.subscribedToLobbyEvents) {
|
||||
console.log("TopNav subscribe to back_to_lobby");
|
||||
this.subscribedToLobbyEvents = true;
|
||||
this.callManager.on(
|
||||
ECallEvents.CALL_VIEW_LOBBY,
|
||||
this.remoteBackToLobby.bind(this)
|
||||
);
|
||||
}
|
||||
if (this.callManager.isHost) return this.user;
|
||||
return this.callManager.peer;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
...mapGetters(["user", "inCall", "callManager"])
|
||||
...mapGetters(["user", "inCall"])
|
||||
},
|
||||
methods: {
|
||||
changeHost() {
|
||||
|
|
Loading…
Reference in a new issue