[mirotalksfu] - refactoring producer

هذا الالتزام موجود في:
Miroslav Pejic
2025-01-14 21:50:55 +01:00
الأصل feac1a1a3a
التزام fda8e5097f
4 ملفات معدلة مع 114 إضافات و139 حذوفات

عرض الملف

@@ -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 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 * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970
* @author Miroslav Pejic - miroslav.pejic.85@gmail.com * @author Miroslav Pejic - miroslav.pejic.85@gmail.com
* @version 1.7.00 * @version 1.7.01
* *
*/ */

عرض الملف

@@ -1,6 +1,6 @@
{ {
"name": "mirotalksfu", "name": "mirotalksfu",
"version": "1.7.00", "version": "1.7.01",
"description": "WebRTC SFU browser-based video calls", "description": "WebRTC SFU browser-based video calls",
"main": "Server.js", "main": "Server.js",
"scripts": { "scripts": {
@@ -79,7 +79,7 @@
"ngrok": "^5.0.0-beta.2", "ngrok": "^5.0.0-beta.2",
"nodemailer": "^6.9.16", "nodemailer": "^6.9.16",
"openai": "^4.78.1", "openai": "^4.78.1",
"qs": "6.13.1", "qs": "6.14.0",
"socket.io": "4.8.1", "socket.io": "4.8.1",
"swagger-ui-express": "5.0.1", "swagger-ui-express": "5.0.1",
"uuid": "11.0.5" "uuid": "11.0.5"

عرض الملف

@@ -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 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 * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970
* @author Miroslav Pejic - miroslav.pejic.85@gmail.com * @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, imageUrl: image.about,
customClass: { image: 'img-about' }, customClass: { image: 'img-about' },
position: 'center', position: 'center',
title: 'WebRTC SFU v1.7.00', title: 'WebRTC SFU v1.7.01',
html: ` html: `
<br /> <br />
<div id="about"> <div id="about">

عرض الملف

@@ -9,7 +9,7 @@
* @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @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 * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970
* @author Miroslav Pejic - miroslav.pejic.85@gmail.com * @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) { async produce(type, deviceId = null, swapCamera = false, init = false) {
let mediaConstraints = {}; let mediaConstraints = {};
let elem;
let stream;
let audio = false; let audio = false;
let video = false;
let screen = false; let screen = false;
switch (type) { switch (type) {
case mediaType.audio: case mediaType.audio:
this.isAudioAllowed = true; this.isAudioAllowed = true;
@@ -1434,6 +1438,7 @@ class RoomClient {
swapCamera swapCamera
? (mediaConstraints = this.getCameraConstraints()) ? (mediaConstraints = this.getCameraConstraints())
: (mediaConstraints = this.getVideoConstraints(deviceId)); : (mediaConstraints = this.getVideoConstraints(deviceId));
video = true;
break; break;
case mediaType.screen: case mediaType.screen:
mediaConstraints = this.getScreenConstraints(); mediaConstraints = this.getScreenConstraints();
@@ -1442,9 +1447,11 @@ class RoomClient {
default: default:
return; return;
} }
if (!this.device.canProduce('video') && !audio) { if (!this.device.canProduce('video') && !audio) {
return console.error('Cannot produce video'); return console.error('Cannot produce video');
} }
if (this.producerLabel.has(type)) { if (this.producerLabel.has(type)) {
return console.warn('Producer already exists for this type ' + type); return console.warn('Producer already exists for this type ' + type);
} }
@@ -1454,7 +1461,6 @@ class RoomClient {
console.log(`Media constraints ${type}:`, mediaConstraints); console.log(`Media constraints ${type}:`, mediaConstraints);
let stream;
try { try {
if (init) { if (init) {
stream = initStream; stream = initStream;
@@ -1487,7 +1493,7 @@ class RoomClient {
}; };
} }
if (!audio && !screen) { if (video) {
const { encodings, codec } = this.getWebCamEncoding(); const { encodings, codec } = this.getWebCamEncoding();
console.log('GET WEBCAM ENCODING', { console.log('GET WEBCAM ENCODING', {
encodings: encodings, encodings: encodings,
@@ -1500,7 +1506,7 @@ class RoomClient {
}; };
} }
if (!audio && screen) { if (screen) {
const { encodings, codec } = this.getScreenEncoding(); const { encodings, codec } = this.getScreenEncoding();
console.log('GET SCREEN ENCODING', { console.log('GET SCREEN ENCODING', {
encodings: encodings, encodings: encodings,
@@ -1535,84 +1541,42 @@ class RoomClient {
this.produceScreenAudio(stream); this.produceScreenAudio(stream);
} }
let elem, au;
if (!audio) { if (!audio) {
this.localVideoStream = stream; 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); 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 // No mirror effect for producer
if (!isInitVideoMirror && elem.classList.contains('mirror')) { if (!isInitVideoMirror && elem.classList.contains('mirror')) {
elem.classList.remove('mirror'); elem.classList.remove('mirror');
} }
//if (!screen && !isEnumerateDevices) enumerateVideoDevices(stream);
} else { } else {
this.localAudioStream = stream; this.localAudioStream = stream;
elem = await this.handleProducer(producer.id, type, stream);
this.audioProducerId = producer.id; this.audioProducerId = producer.id;
au = await this.handleProducer(producer.id, type, stream);
//if (!isEnumerateDevices) enumerateAudioDevices(stream);
getMicrophoneVolumeIndicator(stream); getMicrophoneVolumeIndicator(stream);
} }
if (type == mediaType.video) { if (video) {
this.handleHideMe(); this.handleHideMe();
} }
producer.on('trackended', () => { producer.on('trackended', () => {
console.log('Producer track ended', { id: producer.id, type }); this.closeProducer(type, 'trackended');
this.closeProducer(type);
}); });
producer.on('transportclose', () => { producer.on('transportclose', () => {
console.log('Producer transport close', { id: producer.id, type }); this.closeProducer(type, 'transportclose');
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);
}); });
producer.on('close', () => { producer.on('close', () => {
console.log('Closing producer', { id: producer.id, type }); this.closeProducer(type, 'close');
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);
}); });
switch (type) { switch (type) {
@@ -1987,7 +1951,7 @@ class RoomClient {
} }
closeThenProduce(type, deviceId = null, swapCamera = false) { closeThenProduce(type, deviceId = null, swapCamera = false) {
this.closeProducer(type); this.closeProducer(type, 'closeThenProduce');
setTimeout(async function () { setTimeout(async function () {
await rc.produce(type, deviceId, swapCamera); await rc.produce(type, deviceId, swapCamera);
}, 1000); }, 1000);
@@ -2122,7 +2086,7 @@ class RoomClient {
case mediaType.audio: case mediaType.audio:
elem = document.createElement('audio'); elem = document.createElement('audio');
elem.setAttribute('id', id); elem.setAttribute('id', id);
elem.setAttribute('name', id + '__localAudio'); elem.setAttribute('name', 'LOCAL-AUDIO');
elem.setAttribute('volume', this.peer_id + '___pVolume'); elem.setAttribute('volume', this.peer_id + '___pVolume');
elem.controls = false; elem.controls = false;
elem.autoplay = true; elem.autoplay = true;
@@ -2209,7 +2173,7 @@ class RoomClient {
} }
} }
closeProducer(type) { closeProducer(type, event = 'Close Producer') {
if (!this.producerLabel.has(type)) { if (!this.producerLabel.has(type)) {
return console.warn('There is no producer for this type ' + type); return console.warn('There is no producer for this type ' + type);
} }
@@ -2222,7 +2186,7 @@ class RoomClient {
type: type, type: type,
status: false, status: false,
}; };
console.log(`Close producer ${type}`, data); console.log(`${event} ${type}`, data);
this.socket.emit('producerClosed', data); this.socket.emit('producerClosed', data);
@@ -2230,19 +2194,9 @@ class RoomClient {
this.producers.delete(producer_id); this.producers.delete(producer_id);
this.producerLabel.delete(type); this.producerLabel.delete(type);
console.log('[closeProducer] - PRODUCER LABEL', this.producerLabel); console.log(`[${event}] - PRODUCER LABEL`, this.producerLabel);
if (type !== mediaType.audio) { if (type === mediaType.video || type === mediaType.screen) {
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);
//alert(this.pinnedVideoPlayerId + '==' + producer_id);
if (this.isVideoPinned && this.pinnedVideoPlayerId == producer_id) { if (this.isVideoPinned && this.pinnedVideoPlayerId == producer_id) {
this.removeVideoPinMediaContainer(); this.removeVideoPinMediaContainer();
console.log('Remove pin container due the Producer close', { console.log('Remove pin container due the Producer close', {
@@ -2251,21 +2205,24 @@ class RoomClient {
}); });
} }
handleAspectRatio(); const video = this.getId(producer_id);
this.removeVideoProducer(video, event);
console.log('[producerClose] Video-element-count', this.videoMediaContainer.childElementCount);
} }
if (type === mediaType.audio) { if (type === mediaType.audio) {
const au = this.getName(producer_id + '__localAudio'); const audio = this.getId(producer_id);
au.srcObject.getTracks().forEach(function (track) { this.removeAudioProducer(audio, event);
track.stop(); }
});
this.localAudioEl.removeChild(au); if (type === mediaType.audioTab) {
console.log('[producerClose] Audio-element-count', this.localAudioEl.childElementCount); const auTab = this.getId(producer_id);
this.removeAudioProducer(auTab, event);
} }
switch (type) { switch (type) {
case mediaType.audioTab:
console.log('Closed audio tab');
break;
case mediaType.audio: case mediaType.audio:
this.setIsAudio(this.peer_id, false); this.setIsAudio(this.peer_id, false);
this.event(_EVENTS.stopAudio); this.event(_EVENTS.stopAudio);
@@ -2311,34 +2268,51 @@ class RoomClient {
const sa = await this.handleProducer(producerSa.id, mediaType.audio, stream); const sa = await this.handleProducer(producerSa.id, mediaType.audio, stream);
producerSa.on('trackended', () => { producerSa.on('trackended', () => {
console.log('Producer Screen audio track ended', { id: producerSa.id }); this.closeProducer(mediaType.audioTab, 'trackended');
this.closeProducer(mediaType.audioTab);
}); });
producerSa.on('transportclose', () => { producerSa.on('transportclose', () => {
console.log('Producer Screen audio transport close', { id: producerSa.id }); this.closeProducer(mediaType.audioTab, 'transportclose');
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);
}); });
producerSa.on('close', () => { producerSa.on('close', () => {
console.log('Closing Screen audio producer', { id: producerSa.id }); this.closeProducer(mediaType.audioTab, 'close');
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);
}); });
} catch (err) { } catch (err) {
console.error('Produce Screen Audio error:', 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 // CONSUMER
// #################################################### // ####################################################
@@ -7911,7 +7885,7 @@ class RoomClient {
break; break;
case 'hide': case 'hide':
if (peerActionAllowed) { if (peerActionAllowed) {
this.closeProducer(mediaType.video); this.closeProducer(mediaType.video, 'moderator');
this.userLog( this.userLog(
'warning', 'warning',
from_peer_name + ' ' + _PEER.videoOff + ' has closed yours video', from_peer_name + ' ' + _PEER.videoOff + ' has closed yours video',
@@ -7933,7 +7907,7 @@ class RoomClient {
case 'stop': case 'stop':
if (this.isScreenShareSupported) { if (this.isScreenShareSupported) {
if (peerActionAllowed) { if (peerActionAllowed) {
this.closeProducer(mediaType.screen); this.closeProducer(mediaType.screen, 'moderator');
this.userLog( this.userLog(
'warning', 'warning',
from_peer_name + ' ' + _PEER.screenOff + ' has closed yours screen share', from_peer_name + ' ' + _PEER.screenOff + ' has closed yours screen share',
@@ -8521,39 +8495,8 @@ class RoomClient {
popupPeerInfo(id, peer_info) { popupPeerInfo(id, peer_info) {
if (this.showPeerInfo && !this.isMobileDevice) { 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 // Format the peer info into a structured string
const peerInfoFormatted = emojiPeerInfo const peerInfoFormatted = this.getPeerUiInfos();
.map((item) => `${item.emoji} <b>${item.label}:</b> ${item.value}`)
.join('<br/>');
// Apply the improved Tippy.js tooltip // Apply the improved Tippy.js tooltip
this.setTippy( 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} <b>${item.label}:</b> ${item.value}`).join('<br/>');
}
// #################################################### // ####################################################
// HANDLE PEER GEOLOCATION // HANDLE PEER GEOLOCATION
// #################################################### // ####################################################