diff --git a/app/src/Server.js b/app/src/Server.js
index 06b3e947..ceaf541a 100644
--- a/app/src/Server.js
+++ b/app/src/Server.js
@@ -55,7 +55,7 @@ dev dependencies: {
* @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon
* @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970
* @author Miroslav Pejic - miroslav.pejic.85@gmail.com
- * @version 1.7.00
+ * @version 1.7.01
*
*/
diff --git a/package.json b/package.json
index 7d9e0d20..078000a9 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "mirotalksfu",
- "version": "1.7.00",
+ "version": "1.7.01",
"description": "WebRTC SFU browser-based video calls",
"main": "Server.js",
"scripts": {
@@ -79,7 +79,7 @@
"ngrok": "^5.0.0-beta.2",
"nodemailer": "^6.9.16",
"openai": "^4.78.1",
- "qs": "6.13.1",
+ "qs": "6.14.0",
"socket.io": "4.8.1",
"swagger-ui-express": "5.0.1",
"uuid": "11.0.5"
diff --git a/public/js/Room.js b/public/js/Room.js
index 933ac61f..aff9396a 100644
--- a/public/js/Room.js
+++ b/public/js/Room.js
@@ -11,7 +11,7 @@ if (location.href.substr(0, 5) !== 'https') location.href = 'https' + location.h
* @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon
* @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970
* @author Miroslav Pejic - miroslav.pejic.85@gmail.com
- * @version 1.7.00
+ * @version 1.7.01
*
*/
@@ -4904,7 +4904,7 @@ function showAbout() {
imageUrl: image.about,
customClass: { image: 'img-about' },
position: 'center',
- title: 'WebRTC SFU v1.7.00',
+ title: 'WebRTC SFU v1.7.01',
html: `
diff --git a/public/js/RoomClient.js b/public/js/RoomClient.js
index eac29b51..95e5f51e 100644
--- a/public/js/RoomClient.js
+++ b/public/js/RoomClient.js
@@ -9,7 +9,7 @@
* @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon
* @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970
* @author Miroslav Pejic - miroslav.pejic.85@gmail.com
- * @version 1.7.00
+ * @version 1.7.01
*
*/
@@ -1421,8 +1421,12 @@ class RoomClient {
async produce(type, deviceId = null, swapCamera = false, init = false) {
let mediaConstraints = {};
+ let elem;
+ let stream;
let audio = false;
+ let video = false;
let screen = false;
+
switch (type) {
case mediaType.audio:
this.isAudioAllowed = true;
@@ -1434,6 +1438,7 @@ class RoomClient {
swapCamera
? (mediaConstraints = this.getCameraConstraints())
: (mediaConstraints = this.getVideoConstraints(deviceId));
+ video = true;
break;
case mediaType.screen:
mediaConstraints = this.getScreenConstraints();
@@ -1442,9 +1447,11 @@ class RoomClient {
default:
return;
}
+
if (!this.device.canProduce('video') && !audio) {
return console.error('Cannot produce video');
}
+
if (this.producerLabel.has(type)) {
return console.warn('Producer already exists for this type ' + type);
}
@@ -1454,7 +1461,6 @@ class RoomClient {
console.log(`Media constraints ${type}:`, mediaConstraints);
- let stream;
try {
if (init) {
stream = initStream;
@@ -1487,7 +1493,7 @@ class RoomClient {
};
}
- if (!audio && !screen) {
+ if (video) {
const { encodings, codec } = this.getWebCamEncoding();
console.log('GET WEBCAM ENCODING', {
encodings: encodings,
@@ -1500,7 +1506,7 @@ class RoomClient {
};
}
- if (!audio && screen) {
+ if (screen) {
const { encodings, codec } = this.getScreenEncoding();
console.log('GET SCREEN ENCODING', {
encodings: encodings,
@@ -1535,84 +1541,42 @@ class RoomClient {
this.produceScreenAudio(stream);
}
- let elem, au;
if (!audio) {
this.localVideoStream = stream;
- if (type == mediaType.video) this.videoProducerId = producer.id;
- if (type == mediaType.screen) this.screenProducerId = producer.id;
+
elem = await this.handleProducer(producer.id, type, stream);
+
+ if (video) this.videoProducerId = producer.id;
+ if (screen) this.screenProducerId = producer.id;
+
// No mirror effect for producer
if (!isInitVideoMirror && elem.classList.contains('mirror')) {
elem.classList.remove('mirror');
}
- //if (!screen && !isEnumerateDevices) enumerateVideoDevices(stream);
} else {
this.localAudioStream = stream;
+
+ elem = await this.handleProducer(producer.id, type, stream);
+
this.audioProducerId = producer.id;
- au = await this.handleProducer(producer.id, type, stream);
- //if (!isEnumerateDevices) enumerateAudioDevices(stream);
+
getMicrophoneVolumeIndicator(stream);
}
- if (type == mediaType.video) {
+ if (video) {
this.handleHideMe();
}
producer.on('trackended', () => {
- console.log('Producer track ended', { id: producer.id, type });
- this.closeProducer(type);
+ this.closeProducer(type, 'trackended');
});
producer.on('transportclose', () => {
- console.log('Producer transport close', { id: producer.id, type });
- if (!audio) {
- const d = this.getId(producer.id + '__video');
- const vb = this.getId(producer.id + '__vb');
-
- elem.srcObject.getTracks().forEach(function (track) {
- track.stop();
- });
- elem.parentNode.removeChild(elem);
-
- d.parentNode.removeChild(d);
- vb.parentNode.removeChild(vb);
-
- handleAspectRatio();
- console.log('[transportClose] Video-element-count', this.videoMediaContainer.childElementCount);
- } else {
- au.srcObject.getTracks().forEach(function (track) {
- track.stop();
- });
- au.parentNode.removeChild(au);
- console.log('[transportClose] audio-element-count', this.localAudioEl.childElementCount);
- }
- this.closeProducer(type);
+ this.closeProducer(type, 'transportclose');
});
producer.on('close', () => {
- console.log('Closing producer', { id: producer.id, type });
- if (!audio) {
- const d = this.getId(producer.id + '__video');
- const vb = this.getId(producer.id + '__vb');
-
- elem.srcObject.getTracks().forEach(function (track) {
- track.stop();
- });
- elem.parentNode.removeChild(elem);
-
- d.parentNode.removeChild(d);
- vb.parentNode.removeChild(vb);
-
- handleAspectRatio();
- console.log('[closingProducer] Video-element-count', this.videoMediaContainer.childElementCount);
- } else {
- au.srcObject.getTracks().forEach(function (track) {
- track.stop();
- });
- au.parentNode.removeChild(au);
- console.log('[closingProducer] audio-element-count', this.localAudioEl.childElementCount);
- }
- this.closeProducer(type);
+ this.closeProducer(type, 'close');
});
switch (type) {
@@ -1987,7 +1951,7 @@ class RoomClient {
}
closeThenProduce(type, deviceId = null, swapCamera = false) {
- this.closeProducer(type);
+ this.closeProducer(type, 'closeThenProduce');
setTimeout(async function () {
await rc.produce(type, deviceId, swapCamera);
}, 1000);
@@ -2122,7 +2086,7 @@ class RoomClient {
case mediaType.audio:
elem = document.createElement('audio');
elem.setAttribute('id', id);
- elem.setAttribute('name', id + '__localAudio');
+ elem.setAttribute('name', 'LOCAL-AUDIO');
elem.setAttribute('volume', this.peer_id + '___pVolume');
elem.controls = false;
elem.autoplay = true;
@@ -2209,7 +2173,7 @@ class RoomClient {
}
}
- closeProducer(type) {
+ closeProducer(type, event = 'Close Producer') {
if (!this.producerLabel.has(type)) {
return console.warn('There is no producer for this type ' + type);
}
@@ -2222,7 +2186,7 @@ class RoomClient {
type: type,
status: false,
};
- console.log(`Close producer ${type}`, data);
+ console.log(`${event} ${type}`, data);
this.socket.emit('producerClosed', data);
@@ -2230,19 +2194,9 @@ class RoomClient {
this.producers.delete(producer_id);
this.producerLabel.delete(type);
- console.log('[closeProducer] - PRODUCER LABEL', this.producerLabel);
-
- if (type !== mediaType.audio) {
- const elem = this.getId(producer_id);
- const d = this.getId(producer_id + '__video');
- const vb = this.getId(producer_id + '__vb');
- elem.srcObject.getTracks().forEach(function (track) {
- track.stop();
- });
- d.parentNode.removeChild(d);
- vb.parentNode.removeChild(vb);
+ console.log(`[${event}] - PRODUCER LABEL`, this.producerLabel);
- //alert(this.pinnedVideoPlayerId + '==' + producer_id);
+ if (type === mediaType.video || type === mediaType.screen) {
if (this.isVideoPinned && this.pinnedVideoPlayerId == producer_id) {
this.removeVideoPinMediaContainer();
console.log('Remove pin container due the Producer close', {
@@ -2251,21 +2205,24 @@ class RoomClient {
});
}
- handleAspectRatio();
-
- console.log('[producerClose] Video-element-count', this.videoMediaContainer.childElementCount);
+ const video = this.getId(producer_id);
+ this.removeVideoProducer(video, event);
}
if (type === mediaType.audio) {
- const au = this.getName(producer_id + '__localAudio');
- au.srcObject.getTracks().forEach(function (track) {
- track.stop();
- });
- this.localAudioEl.removeChild(au);
- console.log('[producerClose] Audio-element-count', this.localAudioEl.childElementCount);
+ const audio = this.getId(producer_id);
+ this.removeAudioProducer(audio, event);
+ }
+
+ if (type === mediaType.audioTab) {
+ const auTab = this.getId(producer_id);
+ this.removeAudioProducer(auTab, event);
}
switch (type) {
+ case mediaType.audioTab:
+ console.log('Closed audio tab');
+ break;
case mediaType.audio:
this.setIsAudio(this.peer_id, false);
this.event(_EVENTS.stopAudio);
@@ -2311,34 +2268,51 @@ class RoomClient {
const sa = await this.handleProducer(producerSa.id, mediaType.audio, stream);
producerSa.on('trackended', () => {
- console.log('Producer Screen audio track ended', { id: producerSa.id });
- this.closeProducer(mediaType.audioTab);
+ this.closeProducer(mediaType.audioTab, 'trackended');
});
producerSa.on('transportclose', () => {
- console.log('Producer Screen audio transport close', { id: producerSa.id });
- sa.srcObject.getTracks().forEach(function (track) {
- track.stop();
- });
- sa.parentNode.removeChild(sa);
- console.log('[transportClose] audio-element-count', this.localAudioEl.childElementCount);
- this.closeProducer(mediaType.audioTab);
+ this.closeProducer(mediaType.audioTab, 'transportclose');
});
producerSa.on('close', () => {
- console.log('Closing Screen audio producer', { id: producerSa.id });
- sa.srcObject.getTracks().forEach(function (track) {
- track.stop();
- });
- sa.parentNode.removeChild(sa);
- console.log('[closingProducer] audio-element-count', this.localAudioEl.childElementCount);
- this.closeProducer(mediaType.audioTab);
+ this.closeProducer(mediaType.audioTab, 'close');
});
} catch (err) {
console.error('Produce Screen Audio error:', err);
}
}
+ // ####################################################
+ // REMOVE PRODUCER VIDEO/AUDIO
+ // ####################################################
+
+ removeVideoProducer(video, event) {
+ const d = this.getId(video.id + '__video');
+ const vb = this.getId(video.id + '__vb');
+
+ video.srcObject.getTracks().forEach(function (track) {
+ track.stop();
+ });
+ video.parentNode.removeChild(video);
+
+ d.parentNode.removeChild(d);
+ vb.parentNode.removeChild(vb);
+
+ handleAspectRatio();
+
+ console.log(`[${event}] Video-element-count`, this.videoMediaContainer.childElementCount);
+ }
+
+ removeAudioProducer(audio, event) {
+ audio.srcObject.getTracks().forEach(function (track) {
+ track.stop();
+ });
+ audio.parentNode.removeChild(audio);
+
+ console.log(`[${event}] audio-element-count`, this.localAudioEl.childElementCount);
+ }
+
// ####################################################
// CONSUMER
// ####################################################
@@ -7911,7 +7885,7 @@ class RoomClient {
break;
case 'hide':
if (peerActionAllowed) {
- this.closeProducer(mediaType.video);
+ this.closeProducer(mediaType.video, 'moderator');
this.userLog(
'warning',
from_peer_name + ' ' + _PEER.videoOff + ' has closed yours video',
@@ -7933,7 +7907,7 @@ class RoomClient {
case 'stop':
if (this.isScreenShareSupported) {
if (peerActionAllowed) {
- this.closeProducer(mediaType.screen);
+ this.closeProducer(mediaType.screen, 'moderator');
this.userLog(
'warning',
from_peer_name + ' ' + _PEER.screenOff + ' has closed yours screen share',
@@ -8521,39 +8495,8 @@ class RoomClient {
popupPeerInfo(id, peer_info) {
if (this.showPeerInfo && !this.isMobileDevice) {
- //console.log('POPUP_PEER_INFO', peer_info);
-
- // Destructuring peer_info
- const {
- join_data_time,
- peer_name,
- peer_presenter,
- is_desktop_device,
- is_mobile_device,
- is_tablet_device,
- is_ipad_pro_device,
- os_name,
- os_version,
- browser_name,
- browser_version,
- } = peer_info;
-
- const emojiPeerInfo = [
- { label: 'Join Time', value: join_data_time, emoji: '⏰' },
- { label: 'Name', value: peer_name, emoji: '👤' },
- { label: 'Presenter', value: peer_presenter ? 'Yes' : 'No', emoji: peer_presenter ? '⭐' : '🎤' },
- { label: 'Desktop Device', value: is_desktop_device ? 'Yes' : 'No', emoji: '💻' },
- { label: 'Mobile Device', value: is_mobile_device ? 'Yes' : 'No', emoji: '📱' },
- { label: 'Tablet Device', value: is_tablet_device ? 'Yes' : 'No', emoji: '📲' },
- { label: 'iPad Pro', value: is_ipad_pro_device ? 'Yes' : 'No', emoji: '📱' },
- { label: 'OS', value: `${os_name} ${os_version}`, emoji: '🖥️' },
- { label: 'Browser', value: `${browser_name} ${browser_version}`, emoji: '🌐' },
- ];
-
// Format the peer info into a structured string
- const peerInfoFormatted = emojiPeerInfo
- .map((item) => `${item.emoji} ${item.label}: ${item.value}`)
- .join('
');
+ const peerInfoFormatted = this.getPeerUiInfos();
// Apply the improved Tippy.js tooltip
this.setTippy(
@@ -8565,6 +8508,38 @@ class RoomClient {
}
}
+ getPeerUiInfos() {
+ // console.log('PEER_INFO', peer_info);
+ const {
+ join_data_time,
+ peer_name,
+ peer_presenter,
+ is_desktop_device,
+ is_mobile_device,
+ is_tablet_device,
+ is_ipad_pro_device,
+ os_name,
+ os_version,
+ browser_name,
+ browser_version,
+ } = peer_info;
+
+ const emojiPeerInfo = [
+ { label: 'Join Time', value: join_data_time, emoji: '⏰' },
+ { label: 'Name', value: peer_name, emoji: '👤' },
+ { label: 'Presenter', value: peer_presenter ? 'Yes' : 'No', emoji: peer_presenter ? '⭐' : '🎤' },
+ { label: 'Desktop Device', value: is_desktop_device ? 'Yes' : 'No', emoji: '💻' },
+ { label: 'Mobile Device', value: is_mobile_device ? 'Yes' : 'No', emoji: '📱' },
+ { label: 'Tablet Device', value: is_tablet_device ? 'Yes' : 'No', emoji: '📲' },
+ { label: 'iPad Pro', value: is_ipad_pro_device ? 'Yes' : 'No', emoji: '📱' },
+ { label: 'OS', value: `${os_name} ${os_version}`, emoji: '🖥️' },
+ { label: 'Browser', value: `${browser_name} ${browser_version}`, emoji: '🌐' },
+ ];
+
+ // Format the peer info into a structured string
+ return emojiPeerInfo.map((item) => `${item.emoji} ${item.label}: ${item.value}`).join('
');
+ }
+
// ####################################################
// HANDLE PEER GEOLOCATION
// ####################################################