First version of screen-sharing that works when a user is joining a group after screen sharing begun.

This commit is contained in:
David Négrier 2020-08-20 00:05:00 +02:00
parent 6c5772e849
commit 0119534283
6 changed files with 130 additions and 168 deletions

View file

@ -44,8 +44,6 @@ export class IoSocketController {
private nbClientsGauge: Gauge<string>; private nbClientsGauge: Gauge<string>;
private nbClientsPerRoomGauge: Gauge<string>; private nbClientsPerRoomGauge: Gauge<string>;
private offerScreenSharingByClient: Map<string, Map<string, unknown>> = new Map<string, Map<string, unknown>>();
constructor(server: http.Server) { constructor(server: http.Server) {
this.Io = socketIO(server); this.Io = socketIO(server);
this.nbClientsGauge = new Gauge({ this.nbClientsGauge = new Gauge({
@ -229,11 +227,11 @@ export class IoSocketController {
}); });
socket.on(SockerIoEvent.WEBRTC_SIGNAL, (data: unknown) => { socket.on(SockerIoEvent.WEBRTC_SIGNAL, (data: unknown) => {
this.emit((socket as ExSocketInterface), data, SockerIoEvent.WEBRTC_SIGNAL); this.emitVideo((socket as ExSocketInterface), data);
}); });
socket.on(SockerIoEvent.WEBRTC_SCREEN_SHARING_SIGNAL, (data: unknown) => { socket.on(SockerIoEvent.WEBRTC_SCREEN_SHARING_SIGNAL, (data: unknown) => {
this.emitScreenSharing((socket as ExSocketInterface), data, SockerIoEvent.WEBRTC_SCREEN_SHARING_SIGNAL); this.emitScreenSharing((socket as ExSocketInterface), data);
}); });
socket.on(SockerIoEvent.DISCONNECT, () => { socket.on(SockerIoEvent.DISCONNECT, () => {
@ -280,7 +278,7 @@ export class IoSocketController {
}); });
} }
emit(socket: ExSocketInterface, data: unknown, event: SockerIoEvent){ emitVideo(socket: ExSocketInterface, data: unknown){
if (!isWebRtcSignalMessageInterface(data)) { if (!isWebRtcSignalMessageInterface(data)) {
socket.emit(SockerIoEvent.MESSAGE_ERROR, {message: 'Invalid WEBRTC_SIGNAL message.'}); socket.emit(SockerIoEvent.MESSAGE_ERROR, {message: 'Invalid WEBRTC_SIGNAL message.'});
console.warn('Invalid WEBRTC_SIGNAL message received: ', data); console.warn('Invalid WEBRTC_SIGNAL message received: ', data);
@ -292,25 +290,22 @@ export class IoSocketController {
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.receiverId, " does not exist. This might be a race condition.");
return; return;
} }
return client.emit(event, data); return client.emit(SockerIoEvent.WEBRTC_SIGNAL, data);
} }
emitScreenSharing(socket: ExSocketInterface, data: unknown, event: SockerIoEvent){ emitScreenSharing(socket: ExSocketInterface, data: unknown){
if (!isWebRtcScreenSharingSignalMessageInterface(data)) { if (!isWebRtcSignalMessageInterface(data)) {
socket.emit(SockerIoEvent.MESSAGE_ERROR, {message: 'Invalid WEBRTC_SIGNAL message.'}); socket.emit(SockerIoEvent.MESSAGE_ERROR, {message: 'Invalid WEBRTC_SCREEN_SHARING message.'});
console.warn('Invalid WEBRTC_SIGNAL message received: ', data); console.warn('Invalid WEBRTC_SCREEN_SHARING message received: ', data);
return; return;
} }
if(data.signal.type === "offer"){ //send only at user
let roomOffer = this.offerScreenSharingByClient.get(data.roomId); const client = this.sockets.get(data.receiverId);
if(!roomOffer){ if (client === undefined) {
roomOffer = new Map<string, unknown>(); console.warn("While exchanging a WEBRTC_SCREEN_SHARING signal: client with id ", data.receiverId, " does not exist. This might be a race condition.");
} return;
roomOffer.set(data.userId, data.signal);
this.offerScreenSharingByClient.set(data.roomId, roomOffer);
} }
//share at all others clients send only at user return client.emit(SockerIoEvent.WEBRTC_SCREEN_SHARING_SIGNAL, data);
return socket.in(data.roomId).emit(event, data);
} }
searchClientByIdOrFail(userId: string): ExSocketInterface { searchClientByIdOrFail(userId: string): ExSocketInterface {
@ -393,13 +388,15 @@ export class IoSocketController {
if (this.Io.sockets.adapter.rooms[roomId].length < 2 /*|| this.Io.sockets.adapter.rooms[roomId].length >= 4*/) { if (this.Io.sockets.adapter.rooms[roomId].length < 2 /*|| this.Io.sockets.adapter.rooms[roomId].length >= 4*/) {
return; return;
} }
// TODO: scanning all sockets is maybe not the most efficient
const clients: Array<ExSocketInterface> = (Object.values(this.Io.sockets.sockets) as Array<ExSocketInterface>) const clients: Array<ExSocketInterface> = (Object.values(this.Io.sockets.sockets) as Array<ExSocketInterface>)
.filter((client: ExSocketInterface) => client.webRtcRoomId && client.webRtcRoomId === roomId); .filter((client: ExSocketInterface) => client.webRtcRoomId && client.webRtcRoomId === roomId);
//send start at one client to initialise offer webrtc //send start at one client to initialise offer webrtc
//send all users in room to create PeerConnection in front //send all users in room to create PeerConnection in front
clients.forEach((client: ExSocketInterface, index: number) => { clients.forEach((client: ExSocketInterface, index: number) => {
const clientsId = clients.reduce((tabs: Array<UserInGroupInterface>, clientId: ExSocketInterface, indexClientId: number) => { const peerClients = clients.reduce((tabs: Array<UserInGroupInterface>, clientId: ExSocketInterface, indexClientId: number) => {
if (!clientId.userId || clientId.userId === client.userId) { if (!clientId.userId || clientId.userId === client.userId) {
return tabs; return tabs;
} }
@ -411,7 +408,7 @@ export class IoSocketController {
return tabs; return tabs;
}, []); }, []);
client.emit(SockerIoEvent.WEBRTC_START, {clients: clientsId, roomId: roomId}); client.emit(SockerIoEvent.WEBRTC_START, {clients: peerClients, roomId: roomId});
}); });
} }

View file

@ -12,16 +12,9 @@ export const isWebRtcSignalMessageInterface =
roomId: tg.isString, roomId: tg.isString,
signal: isSignalData signal: isSignalData
}).get(); }).get();
export const isWebRtcScreenSharingSignalMessageInterface =
new tg.IsInterface().withProperties({
userId: tg.isString,
roomId: tg.isString,
signal: isSignalData
}).get();
export const isWebRtcScreenSharingStartMessageInterface = export const isWebRtcScreenSharingStartMessageInterface =
new tg.IsInterface().withProperties({ new tg.IsInterface().withProperties({
userId: tg.isString, userId: tg.isString,
roomId: tg.isString roomId: tg.isString
}).get(); }).get();
export type WebRtcSignalMessageInterface = tg.GuardedType<typeof isWebRtcSignalMessageInterface>; export type WebRtcSignalMessageInterface = tg.GuardedType<typeof isWebRtcSignalMessageInterface>;
export type WebRtcScreenSharingMessageInterface = tg.GuardedType<typeof isWebRtcScreenSharingSignalMessageInterface>;

View file

@ -365,39 +365,3 @@ body {
.chat-mode > div:last-child { .chat-mode > div:last-child {
flex-grow: 5; flex-grow: 5;
} }
/*SCREEN SHARING*/
.active-screen-sharing video{
transform: scaleX(1);
}
.screen-sharing-video-container {
width: 25%;
position: absolute;
}
.active-screen-sharing .screen-sharing-video-container video:hover{
width: 200%;
z-index: 11;
}
.active-screen-sharing .screen-sharing-video-container video{
position: absolute;
width: 100%;
height: auto;
left: 0;
top: 0;
transition: all 0.2s ease;
z-index: 1;
}
.active-screen-sharing .screen-sharing-video-container:nth-child(1){
/*this is for camera of user*/
top: 0%;
}
.active-screen-sharing .screen-sharing-video-container:nth-child(2){
top: 25%;
}
.active-screen-sharing .screen-sharing-video-container:nth-child(3){
top: 50%;
}
.active-screen-sharing .screen-sharing-video-container:nth-child(4) {
top: 75%;
}

View file

@ -80,14 +80,8 @@ export interface WebRtcDisconnectMessageInterface {
} }
export interface WebRtcSignalMessageInterface { export interface WebRtcSignalMessageInterface {
userId: string, userId: string, // TODO: is this needed?
receiverId: string, // TODO: is this needed? (can we merge this with WebRtcScreenSharingMessageInterface?) receiverId: string,
roomId: string,
signal: SignalData
}
export interface WebRtcScreenSharingMessageInterface {
userId: string,
roomId: string, roomId: string,
signal: SignalData signal: SignalData
} }
@ -203,9 +197,10 @@ export class Connection implements Connection {
}); });
} }
public sendWebrtcScreenSharingSignal(signal: unknown, roomId: string, userId? : string|null) { public sendWebrtcScreenSharingSignal(signal: unknown, roomId: string, userId? : string|null, receiverId? : string) {
return this.socket.emit(EventMessage.WEBRTC_SCREEN_SHARING_SIGNAL, { return this.socket.emit(EventMessage.WEBRTC_SCREEN_SHARING_SIGNAL, {
userId: userId, userId: userId ? userId : this.userId,
receiverId: receiverId ? receiverId : this.userId,
roomId: roomId, roomId: roomId,
signal: signal signal: signal
}); });
@ -219,7 +214,7 @@ export class Connection implements Connection {
return this.socket.on(EventMessage.WEBRTC_SIGNAL, callback); return this.socket.on(EventMessage.WEBRTC_SIGNAL, callback);
} }
public receiveWebrtcScreenSharingSignal(callback: (message: WebRtcScreenSharingMessageInterface) => void) { public receiveWebrtcScreenSharingSignal(callback: (message: WebRtcSignalMessageInterface) => void) {
return this.socket.on(EventMessage.WEBRTC_SCREEN_SHARING_SIGNAL, callback); return this.socket.on(EventMessage.WEBRTC_SCREEN_SHARING_SIGNAL, callback);
} }

View file

@ -42,13 +42,13 @@ export class MediaManager {
this.microphoneClose.style.display = "none"; this.microphoneClose.style.display = "none";
this.microphoneClose.addEventListener('click', (e: MouseEvent) => { this.microphoneClose.addEventListener('click', (e: MouseEvent) => {
e.preventDefault(); e.preventDefault();
this.enabledMicrophone(); this.enableMicrophone();
//update tracking //update tracking
}); });
this.microphone = this.getElementByIdOrFail<HTMLImageElement>('microphone'); this.microphone = this.getElementByIdOrFail<HTMLImageElement>('microphone');
this.microphone.addEventListener('click', (e: MouseEvent) => { this.microphone.addEventListener('click', (e: MouseEvent) => {
e.preventDefault(); e.preventDefault();
this.disabledMicrophone(); this.disableMicrophone();
//update tracking //update tracking
}); });
@ -56,13 +56,13 @@ export class MediaManager {
this.cinemaClose.style.display = "none"; this.cinemaClose.style.display = "none";
this.cinemaClose.addEventListener('click', (e: MouseEvent) => { this.cinemaClose.addEventListener('click', (e: MouseEvent) => {
e.preventDefault(); e.preventDefault();
this.enabledCamera(); this.enableCamera();
//update tracking //update tracking
}); });
this.cinema = this.getElementByIdOrFail<HTMLImageElement>('cinema'); this.cinema = this.getElementByIdOrFail<HTMLImageElement>('cinema');
this.cinema.addEventListener('click', (e: MouseEvent) => { this.cinema.addEventListener('click', (e: MouseEvent) => {
e.preventDefault(); e.preventDefault();
this.disabledCamera(); this.disableCamera();
//update tracking //update tracking
}); });
@ -70,24 +70,24 @@ export class MediaManager {
this.monitorClose.style.display = "block"; this.monitorClose.style.display = "block";
this.monitorClose.addEventListener('click', (e: MouseEvent) => { this.monitorClose.addEventListener('click', (e: MouseEvent) => {
e.preventDefault(); e.preventDefault();
this.enabledMonitor(); this.enableScreenSharing();
//update tracking //update tracking
}); });
this.monitor = this.getElementByIdOrFail<HTMLImageElement>('monitor'); this.monitor = this.getElementByIdOrFail<HTMLImageElement>('monitor');
this.monitor.style.display = "none"; this.monitor.style.display = "none";
this.monitor.addEventListener('click', (e: MouseEvent) => { this.monitor.addEventListener('click', (e: MouseEvent) => {
e.preventDefault(); e.preventDefault();
this.disabledMonitor(); this.disableScreenSharing();
//update tracking //update tracking
}); });
} }
onUpdateLocalStream(callback: UpdatedLocalStreamCallback): void { public onUpdateLocalStream(callback: UpdatedLocalStreamCallback): void {
this.updatedLocalStreamCallBacks.add(callback); this.updatedLocalStreamCallBacks.add(callback);
} }
onUpdateScreenSharing(callback: UpdatedScreenSharingCallback): void { public onUpdateScreenSharing(callback: UpdatedScreenSharingCallback): void {
this.updatedScreenSharingCallBacks.add(callback); this.updatedScreenSharingCallBacks.add(callback);
} }
@ -108,12 +108,12 @@ export class MediaManager {
} }
} }
activeVisio(){ showGameOverlay(){
const gameOverlay = this.getElementByIdOrFail('game-overlay'); const gameOverlay = this.getElementByIdOrFail('game-overlay');
gameOverlay.classList.add('active'); gameOverlay.classList.add('active');
} }
enabledCamera() { private enableCamera() {
this.cinemaClose.style.display = "none"; this.cinemaClose.style.display = "none";
this.cinema.style.display = "block"; this.cinema.style.display = "block";
this.constraintsMedia.video = videoConstraint; this.constraintsMedia.video = videoConstraint;
@ -122,7 +122,7 @@ export class MediaManager {
}); });
} }
disabledCamera() { private disableCamera() {
this.cinemaClose.style.display = "block"; this.cinemaClose.style.display = "block";
this.cinema.style.display = "none"; this.cinema.style.display = "none";
this.constraintsMedia.video = false; this.constraintsMedia.video = false;
@ -137,7 +137,7 @@ export class MediaManager {
}); });
} }
enabledMicrophone() { private enableMicrophone() {
this.microphoneClose.style.display = "none"; this.microphoneClose.style.display = "none";
this.microphone.style.display = "block"; this.microphone.style.display = "block";
this.constraintsMedia.audio = true; this.constraintsMedia.audio = true;
@ -146,7 +146,7 @@ export class MediaManager {
}); });
} }
disabledMicrophone() { private disableMicrophone() {
this.microphoneClose.style.display = "block"; this.microphoneClose.style.display = "block";
this.microphone.style.display = "none"; this.microphone.style.display = "none";
this.constraintsMedia.audio = false; this.constraintsMedia.audio = false;
@ -160,7 +160,7 @@ export class MediaManager {
}); });
} }
enabledMonitor() { private enableScreenSharing() {
this.monitorClose.style.display = "none"; this.monitorClose.style.display = "none";
this.monitor.style.display = "block"; this.monitor.style.display = "block";
this.getScreenMedia().then((stream) => { this.getScreenMedia().then((stream) => {
@ -168,7 +168,7 @@ export class MediaManager {
}); });
} }
disabledMonitor() { private disableScreenSharing() {
this.monitorClose.style.display = "block"; this.monitorClose.style.display = "block";
this.monitor.style.display = "none"; this.monitor.style.display = "none";
this.localScreenCapture?.getTracks().forEach((track: MediaStreamTrack) => { this.localScreenCapture?.getTracks().forEach((track: MediaStreamTrack) => {
@ -299,21 +299,18 @@ export class MediaManager {
* @param userId * @param userId
*/ */
addScreenSharingActiveVideo(userId : string){ addScreenSharingActiveVideo(userId : string){
userId = `screen-sharing-${userId}`;
this.webrtcInAudio.play(); this.webrtcInAudio.play();
// FIXME: switch to DisplayManager!
const elementRemoteVideo = this.getElementByIdOrFail("activeScreenSharing"); userId = `screen-sharing-${userId}`;
elementRemoteVideo.insertAdjacentHTML('beforeend', ` const html = `
<div id="div-${userId}" class="screen-sharing-video-container"> <div id="div-${userId}" class="video-container">
<video id="${userId}" autoplay></video> <video id="${userId}" autoplay></video>
</div> </div>
`); `;
const activeHTMLVideoElement : HTMLElement|null = document.getElementById(userId);
if(!activeHTMLVideoElement){ layoutManager.add(DivImportance.Important, userId, html);
return;
} this.remoteVideo.set(userId, this.getElementByIdOrFail<HTMLVideoElement>(userId));
console.log(userId, (activeHTMLVideoElement as HTMLVideoElement));
this.remoteVideo.set(userId, (activeHTMLVideoElement as HTMLVideoElement));
} }
/** /**

View file

@ -1,6 +1,6 @@
import { import {
Connection, Connection,
WebRtcDisconnectMessageInterface, WebRtcScreenSharingMessageInterface, WebRtcDisconnectMessageInterface,
WebRtcSignalMessageInterface, WebRtcSignalMessageInterface,
WebRtcStartMessageInterface WebRtcStartMessageInterface
} from "../Connection"; } from "../Connection";
@ -30,18 +30,18 @@ export class SimplePeer {
private PeerScreenSharingConnectionArray: Map<string, SimplePeerNamespace.Instance> = new Map<string, SimplePeerNamespace.Instance>(); private PeerScreenSharingConnectionArray: Map<string, SimplePeerNamespace.Instance> = new Map<string, SimplePeerNamespace.Instance>();
private PeerConnectionArray: Map<string, SimplePeerNamespace.Instance> = new Map<string, SimplePeerNamespace.Instance>(); private PeerConnectionArray: Map<string, SimplePeerNamespace.Instance> = new Map<string, SimplePeerNamespace.Instance>();
private readonly updateLocalStreamCallback: (media: MediaStream) => void; private readonly sendLocalVideoStreamCallback: (media: MediaStream) => void;
private readonly updateScreenSharingCallback: (media: MediaStream) => void; private readonly sendLocalScreenSharingStreamCallback: (media: MediaStream) => void;
private readonly peerConnectionListeners: Array<PeerConnectionListener> = new Array<PeerConnectionListener>(); private readonly peerConnectionListeners: Array<PeerConnectionListener> = new Array<PeerConnectionListener>();
constructor(Connection: Connection, WebRtcRoomId: string = "test-webrtc") { constructor(Connection: Connection, WebRtcRoomId: string = "test-webrtc") {
this.Connection = Connection; this.Connection = Connection;
this.WebRtcRoomId = WebRtcRoomId; this.WebRtcRoomId = WebRtcRoomId;
// We need to go through this weird bound function pointer in order to be able to "free" this reference later. // We need to go through this weird bound function pointer in order to be able to "free" this reference later.
this.updateLocalStreamCallback = this.updatedLocalStream.bind(this); this.sendLocalVideoStreamCallback = this.sendLocalVideoStream.bind(this);
this.updateScreenSharingCallback = this.updatedScreenSharing.bind(this); this.sendLocalScreenSharingStreamCallback = this.sendLocalScreenSharingStream.bind(this);
mediaManager.onUpdateLocalStream(this.updateLocalStreamCallback); mediaManager.onUpdateLocalStream(this.sendLocalVideoStreamCallback);
mediaManager.onUpdateScreenSharing(this.updateScreenSharingCallback); mediaManager.onUpdateScreenSharing(this.sendLocalScreenSharingStreamCallback);
this.initialise(); this.initialise();
} }
@ -64,11 +64,11 @@ export class SimplePeer {
}); });
//receive signal by gemer //receive signal by gemer
this.Connection.receiveWebrtcScreenSharingSignal((message: WebRtcScreenSharingMessageInterface) => { this.Connection.receiveWebrtcScreenSharingSignal((message: WebRtcSignalMessageInterface) => {
this.receiveWebrtcScreenSharingSignal(message); this.receiveWebrtcScreenSharingSignal(message);
}); });
mediaManager.activeVisio(); mediaManager.showGameOverlay();
mediaManager.getCamera().then(() => { mediaManager.getCamera().then(() => {
//receive message start //receive message start
@ -88,7 +88,7 @@ export class SimplePeer {
private receiveWebrtcStart(data: WebRtcStartMessageInterface) { private receiveWebrtcStart(data: WebRtcStartMessageInterface) {
this.WebRtcRoomId = data.roomId; this.WebRtcRoomId = data.roomId;
this.Users = data.clients; this.Users = data.clients;
// Note: the clients array contain the list of all clients (event 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).
// This would be symmetrical to the way we handle disconnection. // This would be symmetrical to the way we handle disconnection.
@ -102,6 +102,7 @@ export class SimplePeer {
* server has two people connected, start the meet * server has two people connected, start the meet
*/ */
private startWebRtc() { private startWebRtc() {
console.warn('startWebRtc startWebRtc');
this.Users.forEach((user: UserSimplePeerInterface) => { this.Users.forEach((user: UserSimplePeerInterface) => {
//if it's not an initiator, peer connection will be created when gamer will receive offer signal //if it's not an initiator, peer connection will be created when gamer will receive offer signal
if(!user.initiator){ if(!user.initiator){
@ -131,8 +132,11 @@ export class SimplePeer {
} }
if(screenSharing) { if(screenSharing) {
mediaManager.removeActiveScreenSharingVideo(user.userId); // We should display the screen sharing ONLY if we are not initiator
mediaManager.addScreenSharingActiveVideo(user.userId); if (!user.initiator) {
mediaManager.removeActiveScreenSharingVideo(user.userId);
mediaManager.addScreenSharingActiveVideo(user.userId);
}
}else{ }else{
mediaManager.removeActiveVideo(user.userId); mediaManager.removeActiveVideo(user.userId);
mediaManager.addActiveVideo(user.userId, name); mediaManager.addActiveVideo(user.userId, name);
@ -156,17 +160,18 @@ export class SimplePeer {
}); });
if(screenSharing){ if(screenSharing){
this.PeerScreenSharingConnectionArray.set(user.userId, peer); this.PeerScreenSharingConnectionArray.set(user.userId, peer);
}else { } else {
this.PeerConnectionArray.set(user.userId, peer); this.PeerConnectionArray.set(user.userId, peer);
} }
//start listen signal for the peer connection //start listen signal for the peer connection
peer.on('signal', (data: unknown) => { peer.on('signal', (data: unknown) => {
if(screenSharing){ if(screenSharing){
//console.log('Sending WebRTC offer for screen sharing ', data, ' to ', user.userId);
this.sendWebrtcScreenSharingSignal(data, user.userId); this.sendWebrtcScreenSharingSignal(data, user.userId);
return; } else {
this.sendWebrtcSignal(data, user.userId);
} }
this.sendWebrtcSignal(data, user.userId);
}); });
peer.on('stream', (stream: MediaStream) => { peer.on('stream', (stream: MediaStream) => {
@ -197,6 +202,12 @@ export class SimplePeer {
peer.on('connect', () => { peer.on('connect', () => {
mediaManager.isConnected(user.userId); mediaManager.isConnected(user.userId);
console.info(`connect => ${user.userId}`); console.info(`connect => ${user.userId}`);
// When a connection is established to a video stream, and if a screen sharing is taking place,
// the user sharing screen should also initiate a connection to the remote user!
if (screenSharing === false && mediaManager.localScreenCapture) {
this.sendLocalScreenSharingStreamToUser(user.userId);
}
}); });
peer.on('data', (chunk: Buffer) => { peer.on('data', (chunk: Buffer) => {
@ -217,9 +228,9 @@ export class SimplePeer {
}); });
if(screenSharing){ if(screenSharing){
this.addMediaScreenSharing(user.userId); this.pushScreenSharingToRemoteUser(user.userId);
}else { }else {
this.addMedia(user.userId); this.pushVideoToRemoteUser(user.userId);
} }
for (const peerConnectionListener of this.peerConnectionListeners) { for (const peerConnectionListener of this.peerConnectionListeners) {
@ -290,7 +301,7 @@ export class SimplePeer {
* Unregisters any held event handler. * Unregisters any held event handler.
*/ */
public unregister() { public unregister() {
mediaManager.removeUpdateLocalStreamEventListener(this.updateLocalStreamCallback); mediaManager.removeUpdateLocalStreamEventListener(this.sendLocalVideoStreamCallback);
} }
/** /**
@ -299,7 +310,6 @@ export class SimplePeer {
* @param data * @param data
*/ */
private sendWebrtcSignal(data: unknown, userId : string) { private sendWebrtcSignal(data: unknown, userId : string) {
console.log("sendWebrtcSignal", data);
try { try {
this.Connection.sendWebrtcSignal(data, this.WebRtcRoomId, null, userId); this.Connection.sendWebrtcSignal(data, this.WebRtcRoomId, null, userId);
}catch (e) { }catch (e) {
@ -315,7 +325,7 @@ export class SimplePeer {
private sendWebrtcScreenSharingSignal(data: unknown, userId : string) { private sendWebrtcScreenSharingSignal(data: unknown, userId : string) {
console.log("sendWebrtcScreenSharingSignal", data); console.log("sendWebrtcScreenSharingSignal", data);
try { try {
this.Connection.sendWebrtcScreenSharingSignal(data, this.WebRtcRoomId, userId); this.Connection.sendWebrtcScreenSharingSignal(data, this.WebRtcRoomId, null, userId);
}catch (e) { }catch (e) {
console.error(`sendWebrtcScreenSharingSignal => ${userId}`, e); console.error(`sendWebrtcScreenSharingSignal => ${userId}`, e);
} }
@ -339,7 +349,7 @@ export class SimplePeer {
} }
} }
private receiveWebrtcScreenSharingSignal(data: WebRtcScreenSharingMessageInterface) { private receiveWebrtcScreenSharingSignal(data: WebRtcSignalMessageInterface) {
console.log("receiveWebrtcScreenSharingSignal", data); console.log("receiveWebrtcScreenSharingSignal", data);
try { try {
//if offer type, create peer connection //if offer type, create peer connection
@ -384,7 +394,7 @@ export class SimplePeer {
* *
* @param userId * @param userId
*/ */
private addMedia (userId : string) { private pushVideoToRemoteUser(userId : string) {
try { try {
const PeerConnection = this.PeerConnectionArray.get(userId); const PeerConnection = this.PeerConnectionArray.get(userId);
if (!PeerConnection) { if (!PeerConnection) {
@ -396,74 +406,80 @@ export class SimplePeer {
if(!localStream){ if(!localStream){
return; return;
} }
if (localStream) {
for (const track of localStream.getTracks()) { for (const track of localStream.getTracks()) {
PeerConnection.addTrack(track, localStream); PeerConnection.addTrack(track, localStream);
}
} }
}catch (e) { }catch (e) {
console.error(`addMedia => addMedia => ${userId}`, e); console.error(`pushVideoToRemoteUser => ${userId}`, e);
} }
} }
private addMediaScreenSharing(userId : string) { private pushScreenSharingToRemoteUser(userId : string) {
const PeerConnection = this.PeerScreenSharingConnectionArray.get(userId); const PeerConnection = this.PeerScreenSharingConnectionArray.get(userId);
if (!PeerConnection) { if (!PeerConnection) {
throw new Error('While adding media, cannot find user with ID ' + userId); throw new Error('While pushing screen sharing, cannot find user with ID ' + userId);
} }
const localScreenCapture: MediaStream | null = mediaManager.localScreenCapture; const localScreenCapture: MediaStream | null = mediaManager.localScreenCapture;
if(!localScreenCapture){ if(!localScreenCapture){
return; return;
} }
/*for (const track of localScreenCapture.getTracks()) {
for (const track of localScreenCapture.getTracks()) {
PeerConnection.addTrack(track, localScreenCapture); PeerConnection.addTrack(track, localScreenCapture);
}*/ }
return; return;
} }
updatedLocalStream(){ public sendLocalVideoStream(){
this.Users.forEach((user: UserSimplePeerInterface) => { this.Users.forEach((user: UserSimplePeerInterface) => {
this.addMedia(user.userId); this.pushVideoToRemoteUser(user.userId);
}) })
} }
updatedScreenSharing() { /**
* Triggered locally when clicking on the screen sharing button
*/
public sendLocalScreenSharingStream() {
if (mediaManager.localScreenCapture) { if (mediaManager.localScreenCapture) {
for (const user of this.Users) {
//this.Connection.sendWebrtcScreenSharingStart(this.WebRtcRoomId); this.sendLocalScreenSharingStreamToUser(user.userId);
const userId = this.Connection.getUserId();
if(!userId){
return;
} }
const screenSharingUser: UserSimplePeerInterface = {
userId,
initiator: true
};
const 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 {
const userId = this.Connection.getUserId(); for (const user of this.Users) {
if (!userId || !this.PeerScreenSharingConnectionArray.has(userId)) { this.stopLocalScreenSharingStreamToUser(user.userId);
return;
} }
const PeerConnectionScreenSharing = this.PeerScreenSharingConnectionArray.get(userId);
console.log("updatedScreenSharing => destroy", PeerConnectionScreenSharing);
if (!PeerConnectionScreenSharing) {
return;
}
PeerConnectionScreenSharing.destroy();
this.PeerScreenSharingConnectionArray.delete(userId);
} }
} }
private sendLocalScreenSharingStreamToUser(userId: string): void {
// If a connection already exists with user (because it is already sharing a screen with us... let's use this connection)
if (this.PeerScreenSharingConnectionArray.has(userId)) {
this.pushScreenSharingToRemoteUser(userId);
return;
}
const screenSharingUser: UserSimplePeerInterface = {
userId,
initiator: true
};
const PeerConnectionScreenSharing = this.createPeerConnection(screenSharingUser, true);
if (!PeerConnectionScreenSharing) {
return;
}
}
private stopLocalScreenSharingStreamToUser(userId: string): void {
const PeerConnectionScreenSharing = this.PeerScreenSharingConnectionArray.get(userId);
if (!PeerConnectionScreenSharing) {
throw new Error('Weird, screen sharing connection to user ' + userId + 'not found')
}
console.log("updatedScreenSharing => destroy", PeerConnectionScreenSharing);
// FIXME: maybe we don't want to destroy the connexion if it is used in the other way around!
// FIXME: maybe we don't want to destroy the connexion if it is used in the other way around!
// FIXME: maybe we don't want to destroy the connexion if it is used in the other way around!
PeerConnectionScreenSharing.destroy();
this.PeerScreenSharingConnectionArray.delete(userId);
}
} }