Lots of fixes regarding call flow.

This commit is contained in:
Sagi Dayan 2020-05-01 01:55:26 -04:00
parent 64bf37cf59
commit 0c355d549d
18 changed files with 203 additions and 177 deletions

View file

@ -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

View file

@ -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)}`);

View file

@ -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 */

View file

@ -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 */

View file

@ -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

View file

@ -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');
}
}
});

View file

@ -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: () => {}

View file

@ -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;
}
}
};

View file

@ -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>

View file

@ -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;
}
}

View file

@ -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();

View file

@ -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);
}

View file

@ -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() {