diff --git a/app/server.js b/app/server.js
index a1bce1a..0ba8a7b 100755
--- a/app/server.js
+++ b/app/server.js
@@ -404,13 +404,14 @@ function handleConnection(socket) {
if (!users.has(name)) {
users.set(name, socket);
socket.username = name;
-
- // Initialize user media status (default: both enabled)
+
+ // Initialize user media status (default: both enabled, no screen sharing)
userMediaStatus.set(name, {
video: true,
- audio: true
+ audio: true,
+ screenSharing: false,
});
-
+
log.debug('User signed in:', name);
sendMsgTo(socket, { type: 'signIn', success: true });
broadcastConnectedUsers();
@@ -437,7 +438,7 @@ function handleConnection(socket) {
const callerMediaStatus = userMediaStatus.get(socket.username);
const offerData = {
...data,
- callerMediaStatus: callerMediaStatus
+ callerMediaStatus: callerMediaStatus,
};
sendMsgTo(recipientSocket, offerData);
} else {
@@ -461,21 +462,45 @@ function handleConnection(socket) {
// Function to handle media status updates
function handleMediaStatus(data) {
- const { video, audio } = data;
+ const { video, audio, screenSharing } = data;
const username = socket.username;
-
+
if (username && userMediaStatus.has(username)) {
const currentStatus = userMediaStatus.get(username);
const newStatus = {
video: video !== undefined ? video : currentStatus.video,
- audio: audio !== undefined ? audio : currentStatus.audio
+ audio: audio !== undefined ? audio : currentStatus.audio,
+ screenSharing: screenSharing !== undefined ? screenSharing : currentStatus.screenSharing,
};
-
+
userMediaStatus.set(username, newStatus);
log.debug('Updated media status for', username, newStatus);
+
+ // Broadcast screen sharing status change to other connected users if it changed
+ if (screenSharing !== undefined && screenSharing !== currentStatus.screenSharing) {
+ broadcastScreenSharingStatus(username, screenSharing);
+ }
}
}
+ // Function to broadcast screen sharing status to connected users
+ function broadcastScreenSharingStatus(username, isScreenSharing) {
+ const message = {
+ type: 'remoteScreenShare',
+ from: username,
+ screenSharing: isScreenSharing,
+ };
+
+ log.debug('Broadcasting screen sharing status:', message);
+
+ // Send to all other connected users
+ users.forEach((userSocket, userName) => {
+ if (userName !== username) {
+ sendMsgTo(userSocket, message);
+ }
+ });
+ }
+
// Function to handle signaling messages (offer, answer, candidate, leave)
function handleSignalingMessage(data) {
const { type, name } = data;
diff --git a/package-lock.json b/package-lock.json
index b8cbad9..e56d274 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "call-me",
- "version": "1.2.60",
+ "version": "1.2.61",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "call-me",
- "version": "1.2.60",
+ "version": "1.2.61",
"license": "AGPLv3",
"dependencies": {
"@ngrok/ngrok": "1.5.2",
diff --git a/package.json b/package.json
index 75f675d..06568e4 100755
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "call-me",
- "version": "1.2.60",
+ "version": "1.2.61",
"description": "Your Go-To for Instant Video Calls",
"author": "Miroslav Pejic - miroslav.pejic.85@gmail.com",
"license": "AGPLv3",
diff --git a/public/client.js b/public/client.js
index 762f1b1..019425d 100755
--- a/public/client.js
+++ b/public/client.js
@@ -81,6 +81,9 @@ let selectedUser = null;
let unreadMessages = 0;
let currentTab = 'users';
+// Store last applied media status for reapplication after stream connection
+let lastAppliedMediaStatus = null;
+
// Device state
let availableDevices = {
videoInputs: [],
@@ -410,6 +413,9 @@ function handleMessage(data) {
case 'remoteVideo':
handleRemoteVideo(data);
break;
+ case 'remoteScreenShare':
+ handleRemoteScreenShare(data);
+ break;
case 'chat':
addChatMessage(data, false);
break;
@@ -639,10 +645,10 @@ function handleAudioClick() {
const audioTrack = stream.getAudioTracks()[0];
audioTrack.enabled = !audioTrack.enabled;
audioBtn.classList.toggle('btn-danger');
-
+
// Send media status to server
sendMediaStatusToServer();
-
+
sendMsg({
type: 'remoteAudio',
enabled: audioTrack.enabled,
@@ -667,31 +673,18 @@ async function handleScreenShareClick() {
// Update remote video styling based on screen sharing state
function updateRemoteVideoStyling(isScreenSharing) {
+ console.log('updateRemoteVideoStyling called with:', isScreenSharing);
+ console.log('remoteVideo element:', remoteVideo);
+ console.log('remoteVideo has srcObject:', !!remoteVideo?.srcObject);
+
if (isScreenSharing) {
remoteVideo.classList.add('screen-share');
remoteVideo.classList.remove('camera-feed');
- console.log('Remote screen share detected via data channel, classes:', remoteVideo.className);
+ console.log('Applied screen-share styling. Classes:', remoteVideo.className);
} else {
remoteVideo.classList.add('camera-feed');
remoteVideo.classList.remove('screen-share');
- console.log('Remote camera feed detected via data channel, classes:', remoteVideo.className);
- }
-}
-
-// Send screen sharing state to remote peer
-function sendScreenShareState(isSharing) {
- if (thisConnection && thisConnection.dataChannel && thisConnection.dataChannel.readyState === 'open') {
- try {
- thisConnection.dataChannel.send(
- JSON.stringify({
- type: 'screenShareState',
- isScreenSharing: isSharing,
- })
- );
- console.log('Sent screen share state:', isSharing);
- } catch (error) {
- console.error('Error sending screen share state:', error);
- }
+ console.log('Applied camera-feed styling. Classes:', remoteVideo.className);
}
}
@@ -742,8 +735,8 @@ async function startScreenSharing() {
screenShareBtn.title = 'Stop screen sharing';
screenShareBtn.innerHTML = '';
- // Send screen sharing state to remote peer
- sendScreenShareState(true);
+ // Send screen sharing status to server
+ sendMediaStatusToServer();
// Listen for screen share end (user clicks browser's stop sharing)
screenStream.getVideoTracks()[0].onended = () => {
@@ -807,8 +800,8 @@ async function stopScreenSharing() {
screenShareBtn.title = 'Start screen sharing';
screenShareBtn.innerHTML = '';
- // Send screen sharing state to remote peer
- sendScreenShareState(false);
+ // Send screen sharing status to server
+ sendMediaStatusToServer();
// Reset original stream reference
originalStream = null;
@@ -1007,7 +1000,7 @@ async function handleSignIn(data) {
// Initialize device settings after getting media
await initializeDeviceSettings();
handleVideoMirror(localVideo, myStream);
-
+
// Send initial media status to server
sendMediaStatusToServer();
} catch (error) {
@@ -1083,50 +1076,6 @@ function initializeConnection() {
stream.getTracks().forEach((track) => thisConnection.addTrack(track, stream));
- // Create data channel for screen sharing state communication
- thisConnection.dataChannel = thisConnection.createDataChannel('screenShareState', {
- ordered: true,
- });
-
- thisConnection.dataChannel.onopen = () => {
- console.log('Data channel opened');
- // Send current screen sharing state
- thisConnection.dataChannel.send(
- JSON.stringify({
- type: 'screenShareState',
- isScreenSharing: isScreenSharing,
- })
- );
- };
-
- thisConnection.dataChannel.onmessage = (event) => {
- try {
- const data = JSON.parse(event.data);
- if (data.type === 'screenShareState') {
- console.log('Received screen share state:', data.isScreenSharing);
- updateRemoteVideoStyling(data.isScreenSharing);
- }
- } catch (error) {
- console.error('Error parsing data channel message:', error);
- }
- };
-
- // Handle incoming data channels
- thisConnection.ondatachannel = (event) => {
- const channel = event.channel;
- channel.onmessage = (event) => {
- try {
- const data = JSON.parse(event.data);
- if (data.type === 'screenShareState') {
- console.log('Received screen share state via incoming channel:', data.isScreenSharing);
- updateRemoteVideoStyling(data.isScreenSharing);
- }
- } catch (error) {
- console.error('Error parsing incoming data channel message:', error);
- }
- };
- };
-
thisConnection.ontrack = (e) => {
if (e.streams && e.streams[0]) {
const remoteStream = e.streams[0];
@@ -1136,7 +1085,7 @@ function initializeConnection() {
remoteVideo.autoplay = true;
remoteVideo.controls = false;
- // Initial styling - will be updated via data channel
+ // Initial styling - will be updated via server status
remoteVideo.classList.add('camera-feed');
remoteVideo.classList.remove('screen-share');
@@ -1144,6 +1093,9 @@ function initializeConnection() {
renderUserList(); // Update UI to show hang-up button
console.log('Remote stream set to video element');
+
+ // Reapply media status after stream is connected (in case caller had screen sharing on)
+ reapplyRemoteMediaStatus();
} else {
handleError('No stream available in the ontrack event.');
}
@@ -1215,7 +1167,7 @@ function offerAccept(data) {
if (data.callerMediaStatus) {
applyCallerMediaStatus(data.callerMediaStatus);
}
-
+
data.type = 'offerCreate';
socket.recipient = data.from;
} else {
@@ -1363,6 +1315,7 @@ function handleLeave(disconnect = true) {
// Disconnect from server and reset state
disconnectConnection();
connectedUser = null;
+ lastAppliedMediaStatus = null; // Clear stored media status
// Redirect to homepage
window.location.href = '/';
@@ -1393,6 +1346,7 @@ function handleLeave(disconnect = true) {
// Reset state
connectedUser = null;
+ lastAppliedMediaStatus = null; // Clear stored media status
renderUserList();
console.log('Remote user cleanup completed - ready for new connections');
@@ -1449,16 +1403,17 @@ function popupMsg(message, position = 'top', timer = 4000) {
// Send current media status to server
function sendMediaStatusToServer() {
if (!stream) return;
-
+
const videoTrack = stream.getVideoTracks()[0];
const audioTrack = stream.getAudioTracks()[0];
-
+
const mediaStatus = {
type: 'mediaStatus',
video: videoTrack ? videoTrack.enabled : false,
- audio: audioTrack ? audioTrack.enabled : false
+ audio: audioTrack ? audioTrack.enabled : false,
+ screenSharing: isScreenSharing,
};
-
+
socket.emit('message', mediaStatus);
console.log('Sent media status to server:', mediaStatus);
}
@@ -1466,9 +1421,12 @@ function sendMediaStatusToServer() {
// Apply caller's media status to remote video/audio indicators
function applyCallerMediaStatus(callerMediaStatus) {
if (!callerMediaStatus) return;
-
+
console.log('Applying caller media status:', callerMediaStatus);
-
+
+ // Store for potential reapplication after stream connection
+ lastAppliedMediaStatus = callerMediaStatus;
+
// Apply video status
if (!callerMediaStatus.video) {
remoteVideoDisabled.classList.add('show');
@@ -1477,13 +1435,51 @@ function applyCallerMediaStatus(callerMediaStatus) {
remoteVideoDisabled.classList.remove('show');
showCameraOffOverlay('remote', false);
}
-
+
// Apply audio status
if (!callerMediaStatus.audio) {
remoteAudioDisabled.classList.add('show');
} else {
remoteAudioDisabled.classList.remove('show');
}
+
+ // Apply screen sharing status
+ if (callerMediaStatus.screenSharing) {
+ updateRemoteVideoStyling(true);
+ } else {
+ updateRemoteVideoStyling(false);
+ }
+}
+
+// Reapply media status after stream connection
+function reapplyRemoteMediaStatus() {
+ if (lastAppliedMediaStatus) {
+ console.log('Reapplying media status after stream connection:', lastAppliedMediaStatus);
+
+ // Only reapply screen sharing status since video/audio indicators should be preserved
+ if (lastAppliedMediaStatus.screenSharing) {
+ updateRemoteVideoStyling(true);
+ } else {
+ updateRemoteVideoStyling(false);
+ }
+ }
+}
+
+// Handle remote screen sharing status updates
+function handleRemoteScreenShare(data) {
+ const { from, screenSharing } = data;
+
+ // Only apply if this message is from the connected user
+ if (from === connectedUser) {
+ console.log('Remote screen sharing status changed:', screenSharing);
+
+ // Update stored media status
+ if (lastAppliedMediaStatus) {
+ lastAppliedMediaStatus.screenSharing = screenSharing;
+ }
+
+ updateRemoteVideoStyling(screenSharing);
+ }
}
// Send messages to the server