First version of screen-sharing that works when a user is joining a group after screen sharing begun.
This commit is contained in:
parent
6c5772e849
commit
0119534283
@ -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);
|
return client.emit(SockerIoEvent.WEBRTC_SCREEN_SHARING_SIGNAL, data);
|
||||||
this.offerScreenSharingByClient.set(data.roomId, roomOffer);
|
|
||||||
}
|
|
||||||
//share at all others clients send only at user
|
|
||||||
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});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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>;
|
|
||||||
|
36
front/dist/resources/style/style.css
vendored
36
front/dist/resources/style/style.css
vendored
@ -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%;
|
|
||||||
}
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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) {
|
||||||
|
// We should display the screen sharing ONLY if we are not initiator
|
||||||
|
if (!user.initiator) {
|
||||||
mediaManager.removeActiveScreenSharingVideo(user.userId);
|
mediaManager.removeActiveScreenSharingVideo(user.userId);
|
||||||
mediaManager.addScreenSharingActiveVideo(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);
|
||||||
@ -163,10 +167,11 @@ 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) => {
|
||||||
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,46 +406,59 @@ 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.sendLocalScreenSharingStreamToUser(user.userId);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (const user of this.Users) {
|
||||||
|
this.stopLocalScreenSharingStreamToUser(user.userId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//this.Connection.sendWebrtcScreenSharingStart(this.WebRtcRoomId);
|
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)
|
||||||
const userId = this.Connection.getUserId();
|
if (this.PeerScreenSharingConnectionArray.has(userId)) {
|
||||||
if(!userId){
|
this.pushScreenSharingToRemoteUser(userId);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const screenSharingUser: UserSimplePeerInterface = {
|
const screenSharingUser: UserSimplePeerInterface = {
|
||||||
userId,
|
userId,
|
||||||
initiator: true
|
initiator: true
|
||||||
@ -444,26 +467,19 @@ export class SimplePeer {
|
|||||||
if (!PeerConnectionScreenSharing) {
|
if (!PeerConnectionScreenSharing) {
|
||||||
return;
|
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 {
|
|
||||||
const userId = this.Connection.getUserId();
|
|
||||||
if (!userId || !this.PeerScreenSharingConnectionArray.has(userId)) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private stopLocalScreenSharingStreamToUser(userId: string): void {
|
||||||
const PeerConnectionScreenSharing = this.PeerScreenSharingConnectionArray.get(userId);
|
const PeerConnectionScreenSharing = this.PeerScreenSharingConnectionArray.get(userId);
|
||||||
console.log("updatedScreenSharing => destroy", PeerConnectionScreenSharing);
|
|
||||||
if (!PeerConnectionScreenSharing) {
|
if (!PeerConnectionScreenSharing) {
|
||||||
return;
|
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();
|
PeerConnectionScreenSharing.destroy();
|
||||||
this.PeerScreenSharingConnectionArray.delete(userId);
|
this.PeerScreenSharingConnectionArray.delete(userId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user