Switching WebRTC to protobuf + uws

This commit is contained in:
David Négrier 2020-09-29 16:01:22 +02:00
parent a9b1313d39
commit b485c9bf46
7 changed files with 253 additions and 129 deletions

View file

@ -37,7 +37,12 @@ import {
ErrorMessage, ErrorMessage,
RoomJoinedMessage, RoomJoinedMessage,
ItemStateMessage, ItemStateMessage,
ServerToClientMessage, SetUserIdMessage, SilentMessage ServerToClientMessage,
SetUserIdMessage,
SilentMessage,
WebRtcSignalToClientMessage,
WebRtcSignalToServerMessage,
WebRtcStartMessage, WebRtcDisconnectMessage
} from "../Messages/generated/messages_pb"; } from "../Messages/generated/messages_pb";
import {UserMovesMessage} from "../Messages/generated/messages_pb"; import {UserMovesMessage} from "../Messages/generated/messages_pb";
import Direction = PositionMessage.Direction; import Direction = PositionMessage.Direction;
@ -186,7 +191,7 @@ export class IoSocketController {
/* Options */ /* Options */
//compression: uWS.SHARED_COMPRESSOR, //compression: uWS.SHARED_COMPRESSOR,
maxPayloadLength: 16 * 1024 * 1024, maxPayloadLength: 16 * 1024 * 1024,
idleTimeout: 10, //idleTimeout: 10,
/* Handlers */ /* Handlers */
open: (ws) => { open: (ws) => {
this.authenticate(ws); this.authenticate(ws);
@ -222,6 +227,10 @@ export class IoSocketController {
this.handleSilentMessage(client, message.getSilentmessage() as SilentMessage); this.handleSilentMessage(client, message.getSilentmessage() as SilentMessage);
} else if (message.hasItemeventmessage()) { } else if (message.hasItemeventmessage()) {
this.handleItemEvent(client, message.getItemeventmessage() as ItemEventMessage); this.handleItemEvent(client, message.getItemeventmessage() as ItemEventMessage);
} else if (message.hasWebrtcsignaltoservermessage()) {
this.emitVideo(client, message.getWebrtcsignaltoservermessage() as WebRtcSignalToServerMessage)
} else if (message.hasWebrtcscreensharingsignaltoservermessage()) {
this.emitScreenSharing(client, message.getWebrtcscreensharingsignaltoservermessage() as WebRtcSignalToServerMessage)
} }
/* Ok is false if backpressure was built up, wait for drain */ /* Ok is false if backpressure was built up, wait for drain */
@ -282,7 +291,7 @@ export class IoSocketController {
serverToClientMessage.setErrormessage(errorMessage); serverToClientMessage.setErrormessage(errorMessage);
if (!Client.disconnecting) { if (!Client.disconnecting) {
Client.send(serverToClientMessage.serializeBinary().buffer); Client.send(serverToClientMessage.serializeBinary().buffer, true);
} }
console.warn(message); console.warn(message);
} }
@ -496,40 +505,44 @@ export class IoSocketController {
} }
} }
emitVideo(socket: ExSocketInterface, data: unknown){ emitVideo(socket: ExSocketInterface, data: WebRtcSignalToServerMessage): void {
if (!isWebRtcSignalMessageInterface(data)) {
socket.emit(SocketIoEvent.MESSAGE_ERROR, {message: 'Invalid WEBRTC_SIGNAL message.'});
console.warn('Invalid WEBRTC_SIGNAL message received: ', data);
return;
}
//send only at user //send only at user
const client = this.sockets.get(data.receiverId); const client = this.sockets.get(data.getReceiverid());
if (client === undefined) { if (client === undefined) {
console.warn("While exchanging a WebRTC signal: client with id ", data.receiverId, " does not exist. This might be a race condition."); console.warn("While exchanging a WebRTC signal: client with id ", data.getReceiverid(), " does not exist. This might be a race condition.");
return; return;
} }
return client.emit(SocketIoEvent.WEBRTC_SIGNAL, {
userId: socket.userId, const webrtcSignalToClient = new WebRtcSignalToClientMessage();
signal: data.signal webrtcSignalToClient.setUserid(socket.userId);
}); webrtcSignalToClient.setSignal(data.getSignal());
const serverToClientMessage = new ServerToClientMessage();
serverToClientMessage.setWebrtcsignaltoclientmessage(webrtcSignalToClient);
if (!client.disconnecting) {
client.send(serverToClientMessage.serializeBinary().buffer, true);
}
} }
emitScreenSharing(socket: ExSocketInterface, data: unknown){ emitScreenSharing(socket: ExSocketInterface, data: WebRtcSignalToServerMessage): void {
if (!isWebRtcSignalMessageInterface(data)) {
socket.emit(SocketIoEvent.MESSAGE_ERROR, {message: 'Invalid WEBRTC_SCREEN_SHARING message.'});
console.warn('Invalid WEBRTC_SCREEN_SHARING message received: ', data);
return;
}
//send only at user //send only at user
const client = this.sockets.get(data.receiverId); const client = this.sockets.get(data.getReceiverid());
if (client === undefined) { if (client === undefined) {
console.warn("While exchanging a WEBRTC_SCREEN_SHARING signal: client with id ", data.receiverId, " does not exist. This might be a race condition."); console.warn("While exchanging a WEBRTC_SCREEN_SHARING signal: client with id ", data.getReceiverid(), " does not exist. This might be a race condition.");
return; return;
} }
return client.emit(SocketIoEvent.WEBRTC_SCREEN_SHARING_SIGNAL, {
userId: socket.userId, const webrtcSignalToClient = new WebRtcSignalToClientMessage();
signal: data.signal webrtcSignalToClient.setUserid(socket.userId);
}); webrtcSignalToClient.setSignal(data.getSignal());
const serverToClientMessage = new ServerToClientMessage();
serverToClientMessage.setWebrtcscreensharingsignaltoclientmessage(webrtcSignalToClient);
if (!client.disconnecting) {
client.send(serverToClientMessage.serializeBinary().buffer, true);
}
} }
searchClientByIdOrFail(userId: number): ExSocketInterface { searchClientByIdOrFail(userId: number): ExSocketInterface {
@ -571,9 +584,9 @@ export class IoSocketController {
//check and create new world for a room //check and create new world for a room
let world = this.Worlds.get(roomId) let world = this.Worlds.get(roomId)
if(world === undefined){ if(world === undefined){
world = new World((user1: number, group: Group) => { world = new World((user1: User, group: Group) => {
this.connectedUser(user1, group); this.joinWebRtcRoom(user1, group);
}, (user1: number, group: Group) => { }, (user1: User, group: Group) => {
this.disConnectedUser(user1, group); this.disConnectedUser(user1, group);
}, MINIMUM_DISTANCE, GROUP_RADIUS, (thing: Movable, listener: User) => { }, MINIMUM_DISTANCE, GROUP_RADIUS, (thing: Movable, listener: User) => {
const clientListener = this.searchClientByIdOrFail(listener.id); const clientListener = this.searchClientByIdOrFail(listener.id);
@ -677,20 +690,49 @@ export class IoSocketController {
emitInBatch(client, subMessage); emitInBatch(client, subMessage);
} }
/** joinWebRtcRoom(user: User, group: Group) {
* /*const roomId: string = "webrtcroom"+group.getId();
* @param socket if (user.socket.webRtcRoomId === roomId) {
* @param roomId
*/
joinWebRtcRoom(socket: ExSocketInterface, roomId: string) {
// TODO: REBUILD THIS
return;
/* if (socket.webRtcRoomId === roomId) {
return; return;
}*/
// TODO: joinWebRtcRoom will be trigerred twice when joining the first time! Maybe we should fix the GROUP constructor to trigger only one event
console.log('joinWebRtcRoom FOR '+user.socket.name+" "+user.socket.userId);
for (const otherUser of group.getUsers()) {
if (user === otherUser) {
continue;
}
// Let's send 2 messages: one to the user joining the group and one to the other user
const webrtcStartMessage1 = new WebRtcStartMessage();
webrtcStartMessage1.setUserid(otherUser.id);
webrtcStartMessage1.setName(otherUser.socket.name);
webrtcStartMessage1.setInitiator(true);
const serverToClientMessage1 = new ServerToClientMessage();
serverToClientMessage1.setWebrtcstartmessage(webrtcStartMessage1);
if (!user.socket.disconnecting) {
user.socket.send(serverToClientMessage1.serializeBinary().buffer, true);
console.log('Sending webrtcstart initiator to '+user.socket.userId)
}
const webrtcStartMessage2 = new WebRtcStartMessage();
webrtcStartMessage2.setUserid(user.id);
webrtcStartMessage2.setName(user.socket.name);
webrtcStartMessage2.setInitiator(false);
const serverToClientMessage2 = new ServerToClientMessage();
serverToClientMessage2.setWebrtcstartmessage(webrtcStartMessage2);
if (!otherUser.socket.disconnecting) {
otherUser.socket.send(serverToClientMessage2.serializeBinary().buffer, true);
console.log('Sending webrtcstart to '+otherUser.socket.userId)
}
} }
socket.join(roomId);
/* socket.join(roomId);
socket.webRtcRoomId = roomId; socket.webRtcRoomId = roomId;
//if two persons in room share //if two persons in room share
if (this.Io.sockets.adapter.rooms[roomId].length < 2) { if (this.Io.sockets.adapter.rooms[roomId].length < 2) {
@ -737,43 +779,49 @@ export class IoSocketController {
] ]
**/ **/
//connected user
connectedUser(userId: number, group: Group) {
/*let Client = this.sockets.get(userId);
if (Client === undefined) {
return;
}*/
const Client = this.searchClientByIdOrFail(userId);
this.joinWebRtcRoom(Client, "webrtcroom"+group.getId());
}
//disconnect user //disconnect user
disConnectedUser(userId: number, group: Group) { disConnectedUser(user: User, group: Group) {
// TODO: rebuild this
return;
const Client = this.searchClientByIdOrFail(userId); const Client = user.socket;
Client.to("webrtcroom"+group.getId()).emit(SocketIoEvent.WEBRTC_DISCONNECT, {
userId: userId
});
// Most of the time, sending a disconnect event to one of the players is enough (the player will close the connection // Most of the time, sending a disconnect event to one of the players is enough (the player will close the connection
// which will be shut for the other player). // which will be shut for the other player).
// However! In the rare case where the WebRTC connection is not yet established, if we close the connection on one of the player, // However! In the rare case where the WebRTC connection is not yet established, if we close the connection on one of the player,
// the other player will try connecting until a timeout happens (during this time, the connection icon will be displayed for nothing). // the other player will try connecting until a timeout happens (during this time, the connection icon will be displayed for nothing).
// So we also send the disconnect event to the other player. // So we also send the disconnect event to the other player.
for (const user of group.getUsers()) { for (const otherUser of group.getUsers()) {
Client.emit(SocketIoEvent.WEBRTC_DISCONNECT, { if (user === otherUser) {
userId: user.id continue;
}); }
const webrtcDisconnectMessage1 = new WebRtcDisconnectMessage();
webrtcDisconnectMessage1.setUserid(user.id);
const serverToClientMessage1 = new ServerToClientMessage();
serverToClientMessage1.setWebrtcdisconnectmessage(webrtcDisconnectMessage1);
if (!otherUser.socket.disconnecting) {
otherUser.socket.send(serverToClientMessage1.serializeBinary().buffer, true);
}
const webrtcDisconnectMessage2 = new WebRtcDisconnectMessage();
webrtcDisconnectMessage2.setUserid(otherUser.id);
const serverToClientMessage2 = new ServerToClientMessage();
serverToClientMessage2.setWebrtcdisconnectmessage(webrtcDisconnectMessage2);
if (!user.socket.disconnecting) {
user.socket.send(serverToClientMessage2.serializeBinary().buffer, true);
}
} }
//disconnect webrtc room //disconnect webrtc room
if(!Client.webRtcRoomId){ /*if(!Client.webRtcRoomId){
return; return;
} }*/
Client.leave(Client.webRtcRoomId); //Client.leave(Client.webRtcRoomId);
delete Client.webRtcRoomId; //delete Client.webRtcRoomId;
} }
public getWorlds(): Map<string, World> { public getWorlds(): Map<string, World> {

View file

@ -87,7 +87,7 @@ export class Group implements Movable {
join(user: User): void join(user: User): void
{ {
// Broadcast on the right event // Broadcast on the right event
this.connectCallback(user.id, this); this.connectCallback(user, this);
this.users.add(user); this.users.add(user);
user.group = this; user.group = this;
} }
@ -105,7 +105,7 @@ export class Group implements Movable {
} }
// Broadcast on the right event // Broadcast on the right event
this.disconnectCallback(user.id, this); this.disconnectCallback(user, this);
} }
/** /**

View file

@ -4,6 +4,7 @@ import {Zone} from "_Model/Zone";
import {Movable} from "_Model/Movable"; import {Movable} from "_Model/Movable";
import {PositionInterface} from "_Model/PositionInterface"; import {PositionInterface} from "_Model/PositionInterface";
import {PositionNotifier} from "_Model/PositionNotifier"; import {PositionNotifier} from "_Model/PositionNotifier";
import {ExSocketInterface} from "_Model/Websocket/ExSocketInterface";
export class User implements Movable { export class User implements Movable {
public listenedZones: Set<Zone>; public listenedZones: Set<Zone>;
@ -13,7 +14,8 @@ export class User implements Movable {
public id: number, public id: number,
private position: PointInterface, private position: PointInterface,
public silent: boolean, public silent: boolean,
private positionNotifier: PositionNotifier private positionNotifier: PositionNotifier,
public readonly socket: ExSocketInterface
) { ) {
this.listenedZones = new Set<Zone>(); this.listenedZones = new Set<Zone>();

View file

@ -11,8 +11,8 @@ import {PositionNotifier} from "./PositionNotifier";
import {ViewportInterface} from "_Model/Websocket/ViewportMessage"; import {ViewportInterface} from "_Model/Websocket/ViewportMessage";
import {Movable} from "_Model/Movable"; import {Movable} from "_Model/Movable";
export type ConnectCallback = (user: number, group: Group) => void; export type ConnectCallback = (user: User, group: Group) => void;
export type DisconnectCallback = (user: number, group: Group) => void; export type DisconnectCallback = (user: User, group: Group) => void;
export class World { export class World {
private readonly minDistance: number; private readonly minDistance: number;
@ -55,8 +55,8 @@ export class World {
return this.users; return this.users;
} }
public join(socket : Identificable, userPosition: PointInterface): void { public join(socket : ExSocketInterface, userPosition: PointInterface): void {
const user = new User(socket.userId, userPosition, false, this.positionNotifier); const user = new User(socket.userId, userPosition, false, this.positionNotifier, socket);
this.users.set(socket.userId, user); this.users.set(socket.userId, user);
// Let's call update position to trigger the join / leave room // Let's call update position to trigger the join / leave room
//this.updatePosition(socket, userPosition); //this.updatePosition(socket, userPosition);

View file

@ -2,11 +2,27 @@ import Axios from "axios";
import {API_URL} from "./Enum/EnvironmentVariable"; import {API_URL} from "./Enum/EnvironmentVariable";
import {MessageUI} from "./Logger/MessageUI"; import {MessageUI} from "./Logger/MessageUI";
import { import {
BatchMessage, ClientToServerMessage, GroupDeleteMessage, GroupUpdateMessage, ItemEventMessage, JoinRoomMessage, BatchMessage,
PositionMessage, RoomJoinedMessage, ServerToClientMessage, ClientToServerMessage,
SetPlayerDetailsMessage, SetUserIdMessage, SilentMessage, UserJoinedMessage, UserLeftMessage, UserMovedMessage, GroupDeleteMessage,
GroupUpdateMessage,
ItemEventMessage,
JoinRoomMessage,
PositionMessage,
RoomJoinedMessage,
ServerToClientMessage,
SetPlayerDetailsMessage,
SetUserIdMessage,
SilentMessage,
UserJoinedMessage,
UserLeftMessage,
UserMovedMessage,
UserMovesMessage, UserMovesMessage,
ViewportMessage ViewportMessage,
WebRtcDisconnectMessage,
WebRtcSignalToClientMessage,
WebRtcSignalToServerMessage,
WebRtcStartMessage
} from "./Messages/generated/messages_pb" } from "./Messages/generated/messages_pb"
import {PlayerAnimationNames} from "./Phaser/Player/Animation"; import {PlayerAnimationNames} from "./Phaser/Player/Animation";
@ -132,7 +148,7 @@ export interface RoomJoinedMessageInterface {
export class Connection implements Connection { export class Connection implements Connection {
private readonly socket: WebSocket; private readonly socket: WebSocket;
private userId: number|null = null; private userId: number|null = null;
private batchCallbacks: Map<string, Function[]> = new Map<string, Function[]>(); private listeners: Map<string, Function[]> = new Map<string, Function[]>();
private static websocketFactory: null|((url: string)=>any) = null; private static websocketFactory: null|((url: string)=>any) = null;
public static setWebsocketFactory(websocketFactory: (url: string)=>any): void { public static setWebsocketFactory(websocketFactory: (url: string)=>any): void {
@ -185,13 +201,7 @@ export class Connection implements Connection {
throw new Error('Unexpected batch message type'); throw new Error('Unexpected batch message type');
} }
const listeners = this.batchCallbacks.get(event); this.dispatch(event, payload);
if (listeners === undefined) {
continue;
}
for (const listener of listeners) {
listener(payload);
}
} }
} else if (message.hasRoomjoinedmessage()) { } else if (message.hasRoomjoinedmessage()) {
const roomJoinedMessage = message.getRoomjoinedmessage() as RoomJoinedMessage; const roomJoinedMessage = message.getRoomjoinedmessage() as RoomJoinedMessage;
@ -212,11 +222,32 @@ export class Connection implements Connection {
this.userId = (message.getSetuseridmessage() as SetUserIdMessage).getUserid(); this.userId = (message.getSetuseridmessage() as SetUserIdMessage).getUserid();
} else if (message.hasErrormessage()) { } else if (message.hasErrormessage()) {
console.error(EventMessage.MESSAGE_ERROR, message.getErrormessage()?.getMessage); console.error(EventMessage.MESSAGE_ERROR, message.getErrormessage()?.getMessage);
} else if (message.hasWebrtcsignaltoclientmessage()) {
this.dispatch(EventMessage.WEBRTC_SIGNAL, message.getWebrtcsignaltoclientmessage());
} else if (message.hasWebrtcscreensharingsignaltoclientmessage()) {
this.dispatch(EventMessage.WEBRTC_SCREEN_SHARING_SIGNAL, message.getWebrtcscreensharingsignaltoclientmessage());
} else if (message.hasWebrtcstartmessage()) {
console.log('Received WebRtcStartMessage');
this.dispatch(EventMessage.WEBRTC_START, message.getWebrtcstartmessage());
} else if (message.hasWebrtcdisconnectmessage()) {
this.dispatch(EventMessage.WEBRTC_DISCONNECT, message.getWebrtcdisconnectmessage());
} else {
throw new Error('Unknown message received');
} }
} }
} }
private dispatch(event: string, payload: unknown): void {
const listeners = this.listeners.get(event);
if (listeners === undefined) {
return;
}
for (const listener of listeners) {
listener(payload);
}
}
public static createConnection(name: string, characterLayersSelected: string[]): Promise<Connection> { public static createConnection(name: string, characterLayersSelected: string[]): Promise<Connection> {
return Axios.post(`${API_URL}/login`, {name: name}) return Axios.post(`${API_URL}/login`, {name: name})
.then((res) => { .then((res) => {
@ -363,7 +394,7 @@ export class Connection implements Connection {
} }
public onUserJoins(callback: (message: MessageUserJoined) => void): void { public onUserJoins(callback: (message: MessageUserJoined) => void): void {
this.onBatchMessage(EventMessage.JOIN_ROOM, (message: UserJoinedMessage) => { this.onMessage(EventMessage.JOIN_ROOM, (message: UserJoinedMessage) => {
callback(this.toMessageUserJoined(message)); callback(this.toMessageUserJoined(message));
}); });
} }
@ -383,30 +414,30 @@ export class Connection implements Connection {
} }
public onUserMoved(callback: (message: UserMovedMessage) => void): void { public onUserMoved(callback: (message: UserMovedMessage) => void): void {
this.onBatchMessage(EventMessage.USER_MOVED, callback); this.onMessage(EventMessage.USER_MOVED, callback);
//this.socket.on(EventMessage.USER_MOVED, callback); //this.socket.on(EventMessage.USER_MOVED, callback);
} }
/** /**
* Registers a listener on a message that is part of a batch * Registers a listener on a message that is part of a batch
*/ */
private onBatchMessage(eventName: string, callback: Function): void { private onMessage(eventName: string, callback: Function): void {
let callbacks = this.batchCallbacks.get(eventName); let callbacks = this.listeners.get(eventName);
if (callbacks === undefined) { if (callbacks === undefined) {
callbacks = new Array<Function>(); callbacks = new Array<Function>();
this.batchCallbacks.set(eventName, callbacks); this.listeners.set(eventName, callbacks);
} }
callbacks.push(callback); callbacks.push(callback);
} }
public onUserLeft(callback: (userId: number) => void): void { public onUserLeft(callback: (userId: number) => void): void {
this.onBatchMessage(EventMessage.USER_LEFT, (message: UserLeftMessage) => { this.onMessage(EventMessage.USER_LEFT, (message: UserLeftMessage) => {
callback(message.getUserid()); callback(message.getUserid());
}); });
} }
public onGroupUpdatedOrCreated(callback: (groupCreateUpdateMessage: GroupCreatedUpdatedMessageInterface) => void): void { public onGroupUpdatedOrCreated(callback: (groupCreateUpdateMessage: GroupCreatedUpdatedMessageInterface) => void): void {
this.onBatchMessage(EventMessage.GROUP_CREATE_UPDATE, (message: GroupUpdateMessage) => { this.onMessage(EventMessage.GROUP_CREATE_UPDATE, (message: GroupUpdateMessage) => {
callback(this.toGroupCreatedUpdatedMessage(message)); callback(this.toGroupCreatedUpdatedMessage(message));
}); });
} }
@ -424,7 +455,7 @@ export class Connection implements Connection {
} }
public onGroupDeleted(callback: (groupId: number) => void): void { public onGroupDeleted(callback: (groupId: number) => void): void {
this.onBatchMessage(EventMessage.GROUP_DELETE, (message: GroupDeleteMessage) => { this.onMessage(EventMessage.GROUP_DELETE, (message: GroupDeleteMessage) => {
callback(message.getGroupid()); callback(message.getGroupid());
}); });
} }
@ -438,37 +469,58 @@ export class Connection implements Connection {
} }
public sendWebrtcSignal(signal: unknown, receiverId: number) { public sendWebrtcSignal(signal: unknown, receiverId: number) {
/* return this.socket.emit(EventMessage.WEBRTC_SIGNAL, { const webRtcSignal = new WebRtcSignalToServerMessage();
receiverId: receiverId, webRtcSignal.setReceiverid(receiverId);
signal: signal webRtcSignal.setSignal(JSON.stringify(signal));
} as WebRtcSignalSentMessageInterface);*/
const clientToServerMessage = new ClientToServerMessage();
clientToServerMessage.setWebrtcsignaltoservermessage(webRtcSignal);
this.socket.send(clientToServerMessage.serializeBinary().buffer);
} }
public sendWebrtcScreenSharingSignal(signal: unknown, receiverId: number) { public sendWebrtcScreenSharingSignal(signal: unknown, receiverId: number) {
/* return this.socket.emit(EventMessage.WEBRTC_SCREEN_SHARING_SIGNAL, { const webRtcSignal = new WebRtcSignalToServerMessage();
receiverId: receiverId, webRtcSignal.setReceiverid(receiverId);
signal: signal webRtcSignal.setSignal(JSON.stringify(signal));
} as WebRtcSignalSentMessageInterface);*/
const clientToServerMessage = new ClientToServerMessage();
clientToServerMessage.setWebrtcscreensharingsignaltoservermessage(webRtcSignal);
this.socket.send(clientToServerMessage.serializeBinary().buffer);
} }
public receiveWebrtcStart(callback: (message: WebRtcStartMessageInterface) => void) { public receiveWebrtcStart(callback: (message: UserSimplePeerInterface) => void) {
// TODO this.onMessage(EventMessage.WEBRTC_START, (message: WebRtcStartMessage) => {
// this.socket.on(EventMessage.WEBRTC_START, callback); callback({
userId: message.getUserid(),
name: message.getName(),
initiator: message.getInitiator()
});
});
} }
public receiveWebrtcSignal(callback: (message: WebRtcSignalReceivedMessageInterface) => void) { public receiveWebrtcSignal(callback: (message: WebRtcSignalReceivedMessageInterface) => void) {
// TODO this.onMessage(EventMessage.WEBRTC_SIGNAL, (message: WebRtcSignalToClientMessage) => {
// return this.socket.on(EventMessage.WEBRTC_SIGNAL, callback); callback({
userId: message.getUserid(),
signal: JSON.parse(message.getSignal())
});
});
} }
public receiveWebrtcScreenSharingSignal(callback: (message: WebRtcSignalReceivedMessageInterface) => void) { public receiveWebrtcScreenSharingSignal(callback: (message: WebRtcSignalReceivedMessageInterface) => void) {
// TODO this.onMessage(EventMessage.WEBRTC_SCREEN_SHARING_SIGNAL, (message: WebRtcSignalToClientMessage) => {
// return this.socket.on(EventMessage.WEBRTC_SCREEN_SHARING_SIGNAL, callback); callback({
userId: message.getUserid(),
signal: JSON.parse(message.getSignal())
});
});
} }
public onServerDisconnected(callback: (event: CloseEvent) => void): void { public onServerDisconnected(callback: (event: CloseEvent) => void): void {
this.socket.addEventListener('close', (event) => { this.socket.addEventListener('close', (event) => {
console.log('Socket closed with code '+event.code+". Reason: "+event.reason);
if (event.code === 1000) { if (event.code === 1000) {
// Normal closure case // Normal closure case
return; return;
@ -483,8 +535,11 @@ export class Connection implements Connection {
} }
disconnectMessage(callback: (message: WebRtcDisconnectMessageInterface) => void): void { disconnectMessage(callback: (message: WebRtcDisconnectMessageInterface) => void): void {
// TODO this.onMessage(EventMessage.WEBRTC_DISCONNECT, (message: WebRtcDisconnectMessage) => {
// this.socket.on(EventMessage.WEBRTC_DISCONNECT, callback); callback({
userId: message.getUserid()
});
});
} }
emitActionableEvent(itemId: number, event: string, state: unknown, parameters: unknown): void { emitActionableEvent(itemId: number, event: string, state: unknown, parameters: unknown): void {
@ -501,7 +556,7 @@ export class Connection implements Connection {
} }
onActionableEvent(callback: (message: ItemEventMessageInterface) => void): void { onActionableEvent(callback: (message: ItemEventMessageInterface) => void): void {
this.onBatchMessage(EventMessage.ITEM_EVENT, (message: ItemEventMessage) => { this.onMessage(EventMessage.ITEM_EVENT, (message: ItemEventMessage) => {
callback({ callback({
itemId: message.getItemid(), itemId: message.getItemid(),
event: message.getEvent(), event: message.getEvent(),

View file

@ -82,7 +82,7 @@ export class SimplePeer {
mediaManager.getCamera().then(() => { mediaManager.getCamera().then(() => {
//receive message start //receive message start
this.Connection.receiveWebrtcStart((message: WebRtcStartMessageInterface) => { this.Connection.receiveWebrtcStart((message: UserSimplePeerInterface) => {
this.receiveWebrtcStart(message); this.receiveWebrtcStart(message);
}); });
@ -95,17 +95,22 @@ export class SimplePeer {
}); });
} }
private receiveWebrtcStart(data: WebRtcStartMessageInterface) { private receiveWebrtcStart(user: UserSimplePeerInterface) {
this.WebRtcRoomId = data.roomId; //this.WebRtcRoomId = data.roomId;
this.Users = data.clients; this.Users.push(user);
// Note: the clients array contain the list of all clients (even the ones we are already connected to in case a user joints a group) // Note: the clients array contain the list of all clients (even the ones we are already connected to in case a user joints a group)
// So we can receive a request we already had before. (which will abort at the first line of createPeerConnection) // So we can receive a request we already had before. (which will abort at the first line of createPeerConnection)
// TODO: refactor this to only send a message to connect to one user (rather than several users). // TODO: refactor this to only send a message to connect to one user (rather than several users). => DONE
// This would be symmetrical to the way we handle disconnection. // This would be symmetrical to the way we handle disconnection.
//console.log('Start message', data); //console.log('Start message', data);
//start connection //start connection
this.startWebRtc(); //this.startWebRtc();
console.log('receiveWebrtcStart. Initiator: ', user.initiator)
if(!user.initiator){
return;
}
this.createPeerConnection(user);
} }
/** /**
@ -129,6 +134,7 @@ export class SimplePeer {
if( if(
this.PeerConnectionArray.has(user.userId) this.PeerConnectionArray.has(user.userId)
){ ){
console.log('Peer connection already exists to user '+user.userId)
return null; return null;
} }

View file

@ -49,6 +49,11 @@ message UserMovesMessage {
ViewportMessage viewport = 2; ViewportMessage viewport = 2;
} }
message WebRtcSignalToServerMessage {
int32 receiverId = 1;
string signal = 2;
}
message ClientToServerMessage { message ClientToServerMessage {
oneof message { oneof message {
JoinRoomMessage joinRoomMessage = 1; JoinRoomMessage joinRoomMessage = 1;
@ -57,6 +62,8 @@ message ClientToServerMessage {
ViewportMessage viewportMessage = 4; ViewportMessage viewportMessage = 4;
ItemEventMessage itemEventMessage = 5; ItemEventMessage itemEventMessage = 5;
SetPlayerDetailsMessage setPlayerDetailsMessage = 6; SetPlayerDetailsMessage setPlayerDetailsMessage = 6;
WebRtcSignalToServerMessage webRtcSignalToServerMessage = 7;
WebRtcSignalToServerMessage webRtcScreenSharingSignalToServerMessage = 8;
} }
} }
@ -132,14 +139,20 @@ message RoomJoinedMessage {
repeated ItemStateMessage item = 3; repeated ItemStateMessage item = 3;
} }
message WebRtcStartMessage {
int32 userId = 1;
string name = 2;
bool initiator = 3;
}
/*message WebRtcStartMessage { message WebRtcDisconnectMessage {
int32 itemId = 1; int32 userId = 1;
string event = 2; }
string stateJson = 3;
string parametersJson = 4;
}*/
message WebRtcSignalToClientMessage {
int32 userId = 1;
string signal = 2;
}
message ServerToClientMessage { message ServerToClientMessage {
oneof message { oneof message {
@ -147,9 +160,9 @@ message ServerToClientMessage {
ErrorMessage errorMessage = 2; ErrorMessage errorMessage = 2;
RoomJoinedMessage roomJoinedMessage = 3; RoomJoinedMessage roomJoinedMessage = 3;
SetUserIdMessage setUserIdMessage = 4; // TODO: merge this with RoomJoinedMessage ? SetUserIdMessage setUserIdMessage = 4; // TODO: merge this with RoomJoinedMessage ?
// WebRtcStartMessage webRtcStartMessage = 3; WebRtcStartMessage webRtcStartMessage = 5;
// WebRtcSignalMessage webRtcSignalMessage = 4; WebRtcSignalToClientMessage webRtcSignalToClientMessage = 6;
// WebRtcScreenSharingSignalMessage webRtcScreenSharingSignalMessage = 5; WebRtcSignalToClientMessage webRtcScreenSharingSignalToClientMessage = 7;
// WebRtcDisconnectMessage webRtcDisconnectMessage = 6; WebRtcDisconnectMessage webRtcDisconnectMessage = 8;
} }
} }