Create event to start webrtc screen charing

This commit is contained in:
Gregoire Parant 2020-06-14 14:47:16 +02:00 committed by David Négrier
parent a4f42111d7
commit a8f27e6084
5 changed files with 123 additions and 38 deletions

View file

@ -17,7 +17,7 @@ import os from 'os';
import {TokenInterface} from "../Controller/AuthenticateController"; import {TokenInterface} from "../Controller/AuthenticateController";
import {isJoinRoomMessageInterface} from "../Model/Websocket/JoinRoomMessage"; import {isJoinRoomMessageInterface} from "../Model/Websocket/JoinRoomMessage";
import {isPointInterface, PointInterface} from "../Model/Websocket/PointInterface"; import {isPointInterface, PointInterface} from "../Model/Websocket/PointInterface";
import {isWebRtcSignalMessageInterface} from "../Model/Websocket/WebRtcSignalMessage"; import {isWebRtcSignalMessageInterface, isWebRtcScreenSharingSignalMessageInterface, isWebRtcScreenSharingStartMessageInterface} from "../Model/Websocket/WebRtcSignalMessage";
import {UserInGroupInterface} from "../Model/Websocket/UserInGroupInterface"; import {UserInGroupInterface} from "../Model/Websocket/UserInGroupInterface";
enum SockerIoEvent { enum SockerIoEvent {
@ -30,6 +30,7 @@ enum SockerIoEvent {
WEBRTC_SIGNAL = "webrtc-signal", WEBRTC_SIGNAL = "webrtc-signal",
WEBRTC_SCREEN_SHARING_SIGNAL = "webrtc-screen-sharing-signal", WEBRTC_SCREEN_SHARING_SIGNAL = "webrtc-screen-sharing-signal",
WEBRTC_START = "webrtc-start", WEBRTC_START = "webrtc-start",
WEBRTC_SCREEN_SHARING_START = "webrtc-screen-sharing-start",
WEBRTC_DISCONNECT = "webrtc-disconect", WEBRTC_DISCONNECT = "webrtc-disconect",
MESSAGE_ERROR = "message-error", MESSAGE_ERROR = "message-error",
GROUP_CREATE_UPDATE = "group-create-update", GROUP_CREATE_UPDATE = "group-create-update",
@ -231,7 +232,17 @@ export class IoSocketController {
}); });
socket.on(SockerIoEvent.WEBRTC_SCREEN_SHARING_SIGNAL, (data: unknown) => { socket.on(SockerIoEvent.WEBRTC_SCREEN_SHARING_SIGNAL, (data: unknown) => {
this.emit((socket as ExSocketInterface), data, SockerIoEvent.WEBRTC_SCREEN_SHARING_SIGNAL); this.emitScreenSharing((socket as ExSocketInterface), data, SockerIoEvent.WEBRTC_SCREEN_SHARING_SIGNAL);
});
socket.on(SockerIoEvent.WEBRTC_SCREEN_SHARING_START, (data: unknown) => {
console.log(SockerIoEvent.WEBRTC_SCREEN_SHARING_START, data);
if (!isWebRtcScreenSharingStartMessageInterface(data)) {
socket.emit(SockerIoEvent.MESSAGE_ERROR, {message: 'Invalid WEBRTC_SIGNAL message.'});
console.warn('Invalid WEBRTC_SIGNAL message received: ', data);
return;
}
this.Io.in(data.roomId).emit(SockerIoEvent.WEBRTC_SCREEN_SHARING_START, data);
}); });
socket.on(SockerIoEvent.DISCONNECT, () => { socket.on(SockerIoEvent.DISCONNECT, () => {
@ -293,6 +304,16 @@ export class IoSocketController {
return client.emit(event, data); return client.emit(event, data);
} }
emitScreenSharing(socket: ExSocketInterface, data: unknown, event: SockerIoEvent){
if (!isWebRtcScreenSharingSignalMessageInterface(data)) {
socket.emit(SockerIoEvent.MESSAGE_ERROR, {message: 'Invalid WEBRTC_SIGNAL message.'});
console.warn('Invalid WEBRTC_SIGNAL message received: ', data);
return;
}
//share at all others clients send only at user
return socket.broadcast.emit(event, data);
}
searchClientByIdOrFail(userId: string): ExSocketInterface { searchClientByIdOrFail(userId: string): ExSocketInterface {
const client: ExSocketInterface|undefined = this.sockets.get(userId); const client: ExSocketInterface|undefined = this.sockets.get(userId);
if (client === undefined) { if (client === undefined) {

View file

@ -7,4 +7,15 @@ export const isWebRtcSignalMessageInterface =
roomId: tg.isString, roomId: tg.isString,
signal: tg.isUnknown signal: tg.isUnknown
}).get(); }).get();
export const isWebRtcScreenSharingSignalMessageInterface =
new tg.IsInterface().withProperties({
userId: tg.isString,
roomId: tg.isString,
signal: tg.isUnknown
}).get();
export const isWebRtcScreenSharingStartMessageInterface =
new tg.IsInterface().withProperties({
userId: tg.isString,
roomId: tg.isString
}).get();
export type WebRtcSignalMessageInterface = tg.GuardedType<typeof isWebRtcSignalMessageInterface>; export type WebRtcSignalMessageInterface = tg.GuardedType<typeof isWebRtcSignalMessageInterface>;

View file

@ -13,6 +13,7 @@ enum EventMessage{
WEBRTC_SIGNAL = "webrtc-signal", WEBRTC_SIGNAL = "webrtc-signal",
WEBRTC_SCREEN_SHARING_SIGNAL = "webrtc-screen-sharing-signal", WEBRTC_SCREEN_SHARING_SIGNAL = "webrtc-screen-sharing-signal",
WEBRTC_START = "webrtc-start", WEBRTC_START = "webrtc-start",
WEBRTC_SCREEN_SHARING_START = "webrtc-screen-sharing-start",
JOIN_ROOM = "join-room", // bi-directional JOIN_ROOM = "join-room", // bi-directional
USER_POSITION = "user-position", // bi-directional USER_POSITION = "user-position", // bi-directional
USER_MOVED = "user-moved", // From server to client USER_MOVED = "user-moved", // From server to client
@ -197,10 +198,16 @@ export class Connection implements Connection {
}); });
} }
sendWebrtcScreenSharingSignal(signal: any, roomId: string, userId? : string|null, receiverId? : string) { sendWebrtcScreenSharingStart(roomId: string) {
return this.getSocket().emit(EventMessage.WEBRTC_SCREEN_SHARING_START, {
userId: this.userId,
roomId: roomId
});
}
sendWebrtcScreenSharingSignal(signal: any, roomId: string, userId? : string|null) {
return this.getSocket().emit(EventMessage.WEBRTC_SCREEN_SHARING_SIGNAL, { return this.getSocket().emit(EventMessage.WEBRTC_SCREEN_SHARING_SIGNAL, {
userId: userId ? userId : this.userId, userId: userId,
receiverId: receiverId ? receiverId : this.userId,
roomId: roomId, roomId: roomId,
signal: signal signal: signal
}); });
@ -210,6 +217,10 @@ export class Connection implements Connection {
this.socket.on(EventMessage.WEBRTC_START, callback); this.socket.on(EventMessage.WEBRTC_START, callback);
} }
public receiveWebrtcScreenSharingStart(callback: (message: WebRtcDisconnectMessageInterface) => void) {
this.socket.on(EventMessage.WEBRTC_SCREEN_SHARING_START, callback);
}
public receiveWebrtcSignal(callback: (message: WebRtcSignalMessageInterface) => void) { public receiveWebrtcSignal(callback: (message: WebRtcSignalMessageInterface) => void) {
return this.socket.on(EventMessage.WEBRTC_SIGNAL, callback); return this.socket.on(EventMessage.WEBRTC_SIGNAL, callback);
} }

View file

@ -405,6 +405,7 @@ export class MediaManager {
} }
isError(userId : string): void { isError(userId : string): void {
console.log("isError", `div-${userId}`);
const element = document.getElementById(`div-${userId}`); const element = document.getElementById(`div-${userId}`);
if(!element){ if(!element){
return; return;
@ -415,6 +416,10 @@ export class MediaManager {
} }
errorDiv.style.display = 'block'; errorDiv.style.display = 'block';
} }
isErrorScreenSharing(userId : string): void {
this.isError(`screen-sharing-${userId}`);
}
private getSpinner(userId : string): HTMLDivElement|null { private getSpinner(userId : string): HTMLDivElement|null {
const element = document.getElementById(`div-${userId}`); const element = document.getElementById(`div-${userId}`);

View file

@ -63,8 +63,16 @@ export class SimplePeer {
this.receiveWebrtcSignal(message); this.receiveWebrtcSignal(message);
}); });
this.Connection.receiveWebrtcScreenSharingStart((message: WebRtcDisconnectMessageInterface) => {
console.log("receiveWebrtcScreenSharingStart => initiator", message.userId === this.Connection.userId);
if(message.userId === this.Connection.userId) {
console.log("receiveWebrtcScreenSharingStart => initiator => create peer connexion");
this.receiveWebrtcScreenSharingStart(message);
}
});
//receive signal by gemer //receive signal by gemer
this.Connection.receiveWebrtcScreenSharingSignal((message: any) => { this.Connection.receiveWebrtcScreenSharingSignal((message: WebRtcDisconnectMessageInterface) => {
this.receiveWebrtcScreenSharingSignal(message); this.receiveWebrtcScreenSharingSignal(message);
}); });
@ -98,6 +106,31 @@ export class SimplePeer {
this.startWebRtc(); this.startWebRtc();
} }
private receiveWebrtcScreenSharingStart(data: WebRtcDisconnectMessageInterface) {
console.log("receiveWebrtcScreenSharingStart", data);
let screenSharingUser: UserSimplePeerInterface = {
userId: data.userId,
initiator: this.Connection.userId === data.userId
};
let PeerConnectionScreenSharing = this.createPeerConnection(screenSharingUser, true);
if (!PeerConnectionScreenSharing) {
console.error("receiveWebrtcScreenSharingStart => cannot create peer connexion", PeerConnectionScreenSharing);
return;
}
console.log(`receiveWebrtcScreenSharingStart => ${screenSharingUser.initiator}`, mediaManager.localScreenCapture)
if (!mediaManager.localScreenCapture) {
return;
}
try {
for (const track of mediaManager.localScreenCapture.getTracks()) {
PeerConnectionScreenSharing.addTrack(track, mediaManager.localScreenCapture);
}
} catch (e) {
console.error("updatedScreenSharing => ", e);
}
mediaManager.addStreamRemoteScreenSharing(screenSharingUser.userId, mediaManager.localScreenCapture);
}
/** /**
* server has two people connected, start the meet * server has two people connected, start the meet
*/ */
@ -115,8 +148,10 @@ export class SimplePeer {
* create peer connection to bind users * create peer connection to bind users
*/ */
private createPeerConnection(user : UserSimplePeerInterface, screenSharing: boolean = false) : SimplePeerNamespace.Instance | null{ private createPeerConnection(user : UserSimplePeerInterface, screenSharing: boolean = false) : SimplePeerNamespace.Instance | null{
console.log("createPeerConnection => screenSharing", screenSharing) if(
if(this.PeerConnectionArray.has(user.userId)) { (screenSharing && this.PeerScreenSharingConnectionArray.has(user.userId))
|| (!screenSharing && this.PeerConnectionArray.has(user.userId))
){
return null; return null;
} }
@ -128,14 +163,15 @@ export class SimplePeer {
} }
} }
mediaManager.removeActiveVideo(user.userId);
if(screenSharing) { if(screenSharing) {
mediaManager.removeActiveScreenSharingVideo(user.userId);
mediaManager.addScreenSharingActiveVideo(user.userId); mediaManager.addScreenSharingActiveVideo(user.userId);
}else{ }else{
mediaManager.removeActiveVideo(user.userId);
mediaManager.addActiveVideo(user.userId, name); mediaManager.addActiveVideo(user.userId, name);
} }
const peer : SimplePeerNamespace.Instance = new Peer({ const peerOption : SimplePeerNamespace.Instance = new Peer({
initiator: user.initiator ? user.initiator : false, initiator: user.initiator ? user.initiator : false,
reconnectTimer: 10000, reconnectTimer: 10000,
config: { config: {
@ -149,8 +185,10 @@ export class SimplePeer {
credential: 'itcugcOHxle9Acqi$' credential: 'itcugcOHxle9Acqi$'
}, },
] ]
}, }
}); };
console.log("peerOption", peerOption);
let peer : SimplePeerNamespace.Instance = new Peer(peerOption);
if(screenSharing){ if(screenSharing){
this.PeerScreenSharingConnectionArray.set(user.userId, peer); this.PeerScreenSharingConnectionArray.set(user.userId, peer);
}else { }else {
@ -159,7 +197,6 @@ export class SimplePeer {
//start listen signal for the peer connection //start listen signal for the peer connection
peer.on('signal', (data: unknown) => { peer.on('signal', (data: unknown) => {
console.log("screenSharing", screenSharing);
if(screenSharing){ if(screenSharing){
this.sendWebrtcScreenSharingSignal(data, user.userId); this.sendWebrtcScreenSharingSignal(data, user.userId);
return; return;
@ -168,7 +205,7 @@ export class SimplePeer {
}); });
peer.on('stream', (stream: MediaStream) => { peer.on('stream', (stream: MediaStream) => {
this.stream(user.userId, stream); this.stream(user.userId, stream, screenSharing);
}); });
/*peer.on('track', (track: MediaStreamTrack, stream: MediaStream) => { /*peer.on('track', (track: MediaStreamTrack, stream: MediaStream) => {
@ -177,6 +214,7 @@ export class SimplePeer {
peer.on('close', () => { peer.on('close', () => {
if(screenSharing){ if(screenSharing){
this.closeScreenSharingConnection(user.userId); this.closeScreenSharingConnection(user.userId);
return;
} }
this.closeConnection(user.userId); this.closeConnection(user.userId);
}); });
@ -184,6 +222,10 @@ export class SimplePeer {
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
peer.on('error', (err: any) => { peer.on('error', (err: any) => {
console.error(`error => ${user.userId} => ${err.code}`, err); console.error(`error => ${user.userId} => ${err.code}`, err);
if(screenSharing){
//mediaManager.isErrorScreenSharing(user.userId);
return;
}
mediaManager.isError(user.userId); mediaManager.isError(user.userId);
}); });
@ -194,6 +236,7 @@ export class SimplePeer {
peer.on('data', (chunk: Buffer) => { peer.on('data', (chunk: Buffer) => {
let constraint = JSON.parse(chunk.toString('utf8')); let constraint = JSON.parse(chunk.toString('utf8'));
console.log("data", constraint);
if (constraint.audio) { if (constraint.audio) {
mediaManager.enabledMicrophoneByUserId(user.userId); mediaManager.enabledMicrophoneByUserId(user.userId);
} else { } else {
@ -237,7 +280,8 @@ export class SimplePeer {
// I do understand the method closeConnection is called twice, but I don't understand how they manage to run in parallel. // I do understand the method closeConnection is called twice, but I don't understand how they manage to run in parallel.
//console.log('Closing connection with '+userId); //console.log('Closing connection with '+userId);
peer.destroy(); peer.destroy();
this.PeerConnectionArray.delete(userId) this.PeerConnectionArray.delete(userId);
this.closeScreenSharingConnection(userId);
//console.log('Nb users in peerConnectionArray '+this.PeerConnectionArray.size); //console.log('Nb users in peerConnectionArray '+this.PeerConnectionArray.size);
for (const peerConnectionListener of this.peerConnectionListeners) { for (const peerConnectionListener of this.peerConnectionListeners) {
peerConnectionListener.onDisconnect(userId); peerConnectionListener.onDisconnect(userId);
@ -306,7 +350,7 @@ export class SimplePeer {
private sendWebrtcScreenSharingSignal(data: any, userId : string) { private sendWebrtcScreenSharingSignal(data: any, userId : string) {
console.log("sendWebrtcScreenSharingSignal", data); console.log("sendWebrtcScreenSharingSignal", data);
try { try {
this.Connection.sendWebrtcScreenSharingSignal(data, this.WebRtcRoomId, null, userId); this.Connection.sendWebrtcScreenSharingSignal(data, this.WebRtcRoomId, userId);
}catch (e) { }catch (e) {
console.error(`sendWebrtcSignal => ${userId}`, e); console.error(`sendWebrtcSignal => ${userId}`, e);
} }
@ -337,11 +381,11 @@ export class SimplePeer {
if(data.signal.type === "offer"){ if(data.signal.type === "offer"){
this.createPeerConnection(data, true); this.createPeerConnection(data, true);
} }
let peer = this.PeerConnectionArray.get(data.userId); let peer = this.PeerScreenSharingConnectionArray.get(data.userId);
if (peer !== undefined) { if (peer !== undefined) {
peer.signal(data.signal); peer.signal(data.signal);
} else { } else {
console.error('Could not find peer whose ID is "'+data.userId+'" in PeerConnectionArray'); console.error('Could not find peer whose ID is "'+data.userId+'" in receiveWebrtcScreenSharingSignal');
} }
} catch (e) { } catch (e) {
console.error(`receiveWebrtcSignal => ${data.userId}`, e); console.error(`receiveWebrtcSignal => ${data.userId}`, e);
@ -353,7 +397,16 @@ export class SimplePeer {
* @param userId * @param userId
* @param stream * @param stream
*/ */
private stream(userId : string, stream?: MediaStream) { private stream(userId : string, stream?: MediaStream, screenSharing?: boolean) {
console.log(`stream => ${userId} => screenSharing => ${screenSharing}`, stream);
if(screenSharing){
if(!stream){
mediaManager.removeActiveScreenSharingVideo(userId);
return;
}
mediaManager.addStreamRemoteScreenSharing(userId, stream);
return;
}
if(!stream){ if(!stream){
mediaManager.disabledVideoByUserId(userId); mediaManager.disabledVideoByUserId(userId);
mediaManager.disabledMicrophoneByUserId(userId); mediaManager.disabledMicrophoneByUserId(userId);
@ -411,34 +464,18 @@ export class SimplePeer {
updatedScreenSharing() { updatedScreenSharing() {
if (mediaManager.localScreenCapture) { if (mediaManager.localScreenCapture) {
if(!this.Connection.userId){ this.Connection.sendWebrtcScreenSharingStart(this.WebRtcRoomId);
return;
}
let screenSharingUser: UserSimplePeerInterface = {
userId: this.Connection.userId,
initiator: true
};
let PeerConnectionScreenSharing = this.createPeerConnection(screenSharingUser, true);
if (!PeerConnectionScreenSharing) {
return;
}
try {
for (const track of mediaManager.localScreenCapture.getTracks()) {
PeerConnectionScreenSharing.addTrack(track, mediaManager.localScreenCapture);
}
}catch (e) {
console.error("updatedScreenSharing => ", e);
}
mediaManager.addStreamRemoteScreenSharing(screenSharingUser.userId, mediaManager.localScreenCapture);
} else { } else {
if (!this.Connection.userId || !this.PeerScreenSharingConnectionArray.has(this.Connection.userId)) { if (!this.Connection.userId || !this.PeerScreenSharingConnectionArray.has(this.Connection.userId)) {
return; return;
} }
let PeerConnectionScreenSharing = this.PeerScreenSharingConnectionArray.get(this.Connection.userId); let PeerConnectionScreenSharing = this.PeerScreenSharingConnectionArray.get(this.Connection.userId);
console.log("updatedScreenSharing => destroy", PeerConnectionScreenSharing);
if (!PeerConnectionScreenSharing) { if (!PeerConnectionScreenSharing) {
return; return;
} }
PeerConnectionScreenSharing.destroy(); PeerConnectionScreenSharing.destroy();
this.PeerScreenSharingConnectionArray.delete(this.Connection.userId);
} }
} }
} }