[mirotalksfu] - refactoring, update dep.
هذا الالتزام موجود في:
159
app/src/Peer.js
159
app/src/Peer.js
@@ -94,43 +94,54 @@ module.exports = class Peer {
|
||||
}
|
||||
|
||||
async createProducer(producerTransportId, rtpParameters, kind, type) {
|
||||
let producer = await this.transports.get(producerTransportId).produce({
|
||||
kind,
|
||||
rtpParameters,
|
||||
});
|
||||
try {
|
||||
if (!producerTransportId) {
|
||||
throw new Error('Invalid producer transport ID');
|
||||
}
|
||||
|
||||
producer.appData.mediaType = type;
|
||||
const producerTransport = this.transports.get(producerTransportId);
|
||||
if (!producerTransport) {
|
||||
throw new Error(`Producer transport with ID ${producerTransportId} not found`);
|
||||
}
|
||||
|
||||
this.producers.set(producer.id, producer);
|
||||
|
||||
const producerType = producer.type;
|
||||
|
||||
if (['simulcast', 'svc'].includes(producerType)) {
|
||||
const scalabilityMode = producer.rtpParameters.encodings[0].scalabilityMode;
|
||||
const spatialLayer = parseInt(scalabilityMode.substring(1, 2)); // 1/2/3
|
||||
const temporalLayer = parseInt(scalabilityMode.substring(3, 4)); // 1/2/3
|
||||
log.debug(`Producer [${producerType}] ----->`, {
|
||||
scalabilityMode: scalabilityMode,
|
||||
spatialLayer: spatialLayer,
|
||||
temporalLayer: temporalLayer,
|
||||
const producer = await producerTransport.produce({
|
||||
kind,
|
||||
rtpParameters,
|
||||
});
|
||||
} else {
|
||||
log.debug('Producer ----->', { producerType: producerType });
|
||||
}
|
||||
|
||||
producer.on(
|
||||
'transportclose',
|
||||
function () {
|
||||
log.debug('Producer transport close', {
|
||||
peer_name: this.peer_info.peer_name,
|
||||
consumer_id: producer.id,
|
||||
producer.appData.mediaType = type;
|
||||
|
||||
this.producers.set(producer.id, producer);
|
||||
|
||||
const producerType = producer.type;
|
||||
|
||||
if (['simulcast', 'svc'].includes(producerType)) {
|
||||
const { scalabilityMode } = producer.rtpParameters.encodings[0];
|
||||
const spatialLayer = parseInt(scalabilityMode.substring(1, 2)); // 1/2/3
|
||||
const temporalLayer = parseInt(scalabilityMode.substring(3, 4)); // 1/2/3
|
||||
log.debug(`Producer [${producerType}] created with ID ${producer.id}`, {
|
||||
scalabilityMode,
|
||||
spatialLayer,
|
||||
temporalLayer,
|
||||
});
|
||||
} else {
|
||||
log.debug(`Producer of type ${producerType} created with ID ${producer.id}`);
|
||||
}
|
||||
|
||||
producer.on('transportclose', () => {
|
||||
log.debug('Producer transport closed', {
|
||||
peer_name: this.peer_info?.peer_name,
|
||||
producer_id: producer.id,
|
||||
});
|
||||
producer.close();
|
||||
this.producers.delete(producer.id);
|
||||
}.bind(this),
|
||||
);
|
||||
});
|
||||
|
||||
return producer;
|
||||
return producer;
|
||||
} catch (error) {
|
||||
log.error('Error creating producer', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
closeProducer(producer_id) {
|
||||
@@ -148,66 +159,64 @@ module.exports = class Peer {
|
||||
// ####################################################
|
||||
|
||||
async createConsumer(consumer_transport_id, producer_id, rtpCapabilities) {
|
||||
let consumerTransport = this.transports.get(consumer_transport_id);
|
||||
let consumer = null;
|
||||
|
||||
try {
|
||||
consumer = await consumerTransport.consume({
|
||||
const consumerTransport = this.transports.get(consumer_transport_id);
|
||||
|
||||
if (!consumerTransport) {
|
||||
throw new Error(`Consumer transport with id ${consumer_transport_id} not found`);
|
||||
}
|
||||
|
||||
const consumer = await consumerTransport.consume({
|
||||
producerId: producer_id,
|
||||
rtpCapabilities,
|
||||
enableRtx: true, // Enable NACK for OPUS.
|
||||
paused: false,
|
||||
});
|
||||
} catch (error) {
|
||||
return console.error('Consume failed', error);
|
||||
}
|
||||
|
||||
const consumerType = consumer.type;
|
||||
const consumerType = consumer.type;
|
||||
|
||||
// https://www.w3.org/TR/webrtc-svc/#scalabilitymodes*
|
||||
if (['simulcast', 'svc'].includes(consumerType)) {
|
||||
const { scalabilityMode } = consumer.rtpParameters.encodings[0];
|
||||
const spatialLayer = parseInt(scalabilityMode.substring(1, 2)); // 1/2/3
|
||||
const temporalLayer = parseInt(scalabilityMode.substring(3, 4)); // 1/2/3
|
||||
await consumer.setPreferredLayers({
|
||||
spatialLayer: spatialLayer,
|
||||
temporalLayer: temporalLayer,
|
||||
});
|
||||
log.debug(`Consumer [${consumerType}] ----->`, {
|
||||
scalabilityMode,
|
||||
spatialLayer,
|
||||
temporalLayer,
|
||||
});
|
||||
} else {
|
||||
log.debug('Consumer ----->', { type: consumerType });
|
||||
}
|
||||
|
||||
if (['simulcast', 'svc'].includes(consumerType)) {
|
||||
// simulcast - L1T3/L2T3/L3T3 | svc - L3T3
|
||||
const scalabilityMode = consumer.rtpParameters.encodings[0].scalabilityMode;
|
||||
const spatialLayer = parseInt(scalabilityMode.substring(1, 2)); // 1/2/3
|
||||
const temporalLayer = parseInt(scalabilityMode.substring(3, 4)); // 1/2/3
|
||||
await consumer.setPreferredLayers({
|
||||
spatialLayer: spatialLayer,
|
||||
temporalLayer: temporalLayer,
|
||||
});
|
||||
log.debug(`Consumer [${consumerType}] ----->`, {
|
||||
scalabilityMode: scalabilityMode,
|
||||
spatialLayer: spatialLayer,
|
||||
temporalLayer: temporalLayer,
|
||||
});
|
||||
} else {
|
||||
log.debug('Consumer ----->', { consumerType: consumerType });
|
||||
}
|
||||
|
||||
this.consumers.set(consumer.id, consumer);
|
||||
|
||||
consumer.on(
|
||||
'transportclose',
|
||||
function () {
|
||||
consumer.on('transportclose', () => {
|
||||
log.debug('Consumer transport close', {
|
||||
peer_name: this.peer_info.peer_name,
|
||||
peer_name: this.peer_info?.peer_name,
|
||||
consumer_id: consumer.id,
|
||||
});
|
||||
this.removeConsumer(consumer.id);
|
||||
}.bind(this),
|
||||
);
|
||||
});
|
||||
|
||||
return {
|
||||
consumer,
|
||||
params: {
|
||||
producerId: producer_id,
|
||||
id: consumer.id,
|
||||
kind: consumer.kind,
|
||||
rtpParameters: consumer.rtpParameters,
|
||||
type: consumer.type,
|
||||
producerPaused: consumer.producerPaused,
|
||||
},
|
||||
};
|
||||
this.consumers.set(consumer.id, consumer);
|
||||
|
||||
return {
|
||||
consumer,
|
||||
params: {
|
||||
producerId: producer_id,
|
||||
id: consumer.id,
|
||||
kind: consumer.kind,
|
||||
rtpParameters: consumer.rtpParameters,
|
||||
type: consumer.type,
|
||||
producerPaused: consumer.producerPaused,
|
||||
},
|
||||
};
|
||||
} catch (error) {
|
||||
log.error('Error creating consumer', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
removeConsumer(consumer_id) {
|
||||
|
||||
265
app/src/Room.js
265
app/src/Room.js
@@ -35,7 +35,9 @@ module.exports = class Room {
|
||||
this.redirect = config.redirect;
|
||||
this.peers = new Map();
|
||||
this.bannedPeers = [];
|
||||
this.webRtcTransport = config.mediasoup.webRtcTransport;
|
||||
this.router = null;
|
||||
this.routerSettings = config.mediasoup.router;
|
||||
this.createTheRouter();
|
||||
}
|
||||
|
||||
@@ -44,19 +46,17 @@ module.exports = class Room {
|
||||
// ####################################################
|
||||
|
||||
createTheRouter() {
|
||||
const { mediaCodecs } = config.mediasoup.router;
|
||||
const { mediaCodecs } = this.routerSettings;
|
||||
this.worker
|
||||
.createRouter({
|
||||
mediaCodecs,
|
||||
})
|
||||
.then(
|
||||
function (router) {
|
||||
this.router = router;
|
||||
if (this.audioLevelObserverEnabled) {
|
||||
this.startAudioLevelObservation(router);
|
||||
}
|
||||
}.bind(this),
|
||||
);
|
||||
.then((router) => {
|
||||
this.router = router;
|
||||
if (this.audioLevelObserverEnabled) {
|
||||
this.startAudioLevelObservation(router);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ####################################################
|
||||
@@ -81,26 +81,36 @@ module.exports = class Room {
|
||||
}
|
||||
|
||||
sendActiveSpeakerVolume(volumes) {
|
||||
if (Date.now() > this.audioLastUpdateTime + 100) {
|
||||
this.audioLastUpdateTime = Date.now();
|
||||
const { producer, volume } = volumes[0];
|
||||
let audioVolume = Math.round(Math.pow(10, volume / 70) * 10); // 1-10
|
||||
if (audioVolume > 1) {
|
||||
// log.debug('PEERS', this.peers);
|
||||
this.peers.forEach((peer) => {
|
||||
peer.producers.forEach((peerProducer) => {
|
||||
if (
|
||||
producer.id === peerProducer.id &&
|
||||
peerProducer.kind == 'audio' &&
|
||||
peer.peer_audio === true
|
||||
) {
|
||||
let data = { peer_name: peer.peer_name, peer_id: peer.id, audioVolume: audioVolume };
|
||||
//log.debug('audioLevelObserver id [' + this.id + ']', data);
|
||||
this.broadCast(0, 'audioVolume', data);
|
||||
}
|
||||
});
|
||||
});
|
||||
try {
|
||||
if (!Array.isArray(volumes) || volumes.length === 0) {
|
||||
throw new Error('Invalid volumes array');
|
||||
}
|
||||
|
||||
if (Date.now() > this.audioLastUpdateTime + 100) {
|
||||
this.audioLastUpdateTime = Date.now();
|
||||
|
||||
const { producer, volume } = volumes[0];
|
||||
const audioVolume = Math.round(Math.pow(10, volume / 70) * 10); // Scale volume to 1-10
|
||||
|
||||
if (audioVolume > 1) {
|
||||
this.peers.forEach((peer) => {
|
||||
peer.producers.forEach((peerProducer) => {
|
||||
if (peerProducer.id === producer.id && peerProducer.kind === 'audio' && peer.peer_audio) {
|
||||
const data = {
|
||||
peer_name: peer.peer_name,
|
||||
peer_id: peer.id,
|
||||
audioVolume: audioVolume,
|
||||
};
|
||||
// Uncomment the following line for debugging
|
||||
// log.debug('Sending audio volume:', data);
|
||||
this.broadCast(0, 'audioVolume', data);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
log.error('Error sending active speaker volume', error);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,7 +198,7 @@ module.exports = class Room {
|
||||
}
|
||||
|
||||
getProducerListForPeer() {
|
||||
let producerList = [];
|
||||
const producerList = [];
|
||||
this.peers.forEach((peer) => {
|
||||
peer.producers.forEach((producer) => {
|
||||
producerList.push({
|
||||
@@ -203,8 +213,19 @@ module.exports = class Room {
|
||||
}
|
||||
|
||||
async connectPeerTransport(socket_id, transport_id, dtlsParameters) {
|
||||
if (!this.peers.has(socket_id)) return;
|
||||
await this.peers.get(socket_id).connectTransport(transport_id, dtlsParameters);
|
||||
try {
|
||||
if (!socket_id || !transport_id || !dtlsParameters) {
|
||||
throw new Error('Invalid input parameters');
|
||||
}
|
||||
|
||||
if (!this.peers.has(socket_id)) {
|
||||
throw new Error(`Peer with socket ID ${socket_id} not found`);
|
||||
}
|
||||
|
||||
await this.peers.get(socket_id).connectTransport(transport_id, dtlsParameters);
|
||||
} catch (error) {
|
||||
log.error('Error connecting peer transport', error);
|
||||
}
|
||||
}
|
||||
|
||||
async removePeer(socket_id) {
|
||||
@@ -218,46 +239,50 @@ module.exports = class Room {
|
||||
// ####################################################
|
||||
|
||||
async createWebRtcTransport(socket_id) {
|
||||
const { maxIncomingBitrate, initialAvailableOutgoingBitrate, listenInfos } = config.mediasoup.webRtcTransport;
|
||||
try {
|
||||
if (!socket_id || !this.peers.has(socket_id)) {
|
||||
throw new Error(`Invalid socket ID: ${socket_id}`);
|
||||
}
|
||||
|
||||
const transport = await this.router.createWebRtcTransport({
|
||||
listenInfos: listenInfos,
|
||||
enableUdp: true,
|
||||
enableTcp: true,
|
||||
preferUdp: true,
|
||||
initialAvailableOutgoingBitrate,
|
||||
});
|
||||
const { maxIncomingBitrate, initialAvailableOutgoingBitrate, listenInfos } = this.webRtcTransport;
|
||||
const transport = await this.router.createWebRtcTransport({
|
||||
listenInfos: listenInfos,
|
||||
enableUdp: true,
|
||||
enableTcp: true,
|
||||
preferUdp: true,
|
||||
initialAvailableOutgoingBitrate,
|
||||
});
|
||||
|
||||
if (maxIncomingBitrate) {
|
||||
try {
|
||||
if (maxIncomingBitrate) {
|
||||
await transport.setMaxIncomingBitrate(maxIncomingBitrate);
|
||||
} catch (error) {}
|
||||
}
|
||||
}
|
||||
|
||||
transport.on(
|
||||
'dtlsstatechange',
|
||||
function (dtlsState) {
|
||||
transport.on('dtlsstatechange', (dtlsState) => {
|
||||
if (dtlsState === 'closed') {
|
||||
log.debug('Transport close', { peer_name: this.peers.get(socket_id).peer_name });
|
||||
log.debug('Transport closed', { peer_name: this.peers.get(socket_id)?.peer_name });
|
||||
transport.close();
|
||||
}
|
||||
}.bind(this),
|
||||
);
|
||||
});
|
||||
|
||||
transport.on('close', () => {
|
||||
log.debug('Transport close', { peer_name: this.peers.get(socket_id).peer_name });
|
||||
});
|
||||
transport.on('close', () => {
|
||||
log.debug('Transport closed', { peer_name: this.peers.get(socket_id)?.peer_name });
|
||||
});
|
||||
|
||||
log.debug('Adding transport', { transportId: transport.id });
|
||||
this.peers.get(socket_id).addTransport(transport);
|
||||
return {
|
||||
params: {
|
||||
id: transport.id,
|
||||
iceParameters: transport.iceParameters,
|
||||
iceCandidates: transport.iceCandidates,
|
||||
dtlsParameters: transport.dtlsParameters,
|
||||
},
|
||||
};
|
||||
log.debug('Adding transport', { transportId: transport.id });
|
||||
this.peers.get(socket_id)?.addTransport(transport);
|
||||
|
||||
return {
|
||||
params: {
|
||||
id: transport.id,
|
||||
iceParameters: transport.iceParameters,
|
||||
iceCandidates: transport.iceCandidates,
|
||||
dtlsParameters: transport.dtlsParameters,
|
||||
},
|
||||
};
|
||||
} catch (error) {
|
||||
log.error('Error creating WebRTC transport', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// ####################################################
|
||||
@@ -265,23 +290,37 @@ module.exports = class Room {
|
||||
// ####################################################
|
||||
|
||||
async produce(socket_id, producerTransportId, rtpParameters, kind, type) {
|
||||
return new Promise(
|
||||
async function (resolve, reject) {
|
||||
let producer = await this.peers
|
||||
.get(socket_id)
|
||||
.createProducer(producerTransportId, rtpParameters, kind, type);
|
||||
resolve(producer.id);
|
||||
this.broadCast(socket_id, 'newProducers', [
|
||||
{
|
||||
producer_id: producer.id,
|
||||
producer_socket_id: socket_id,
|
||||
peer_name: this.peers.get(socket_id)?.peer_name,
|
||||
peer_info: this.peers.get(socket_id)?.peer_info,
|
||||
type: type,
|
||||
},
|
||||
]);
|
||||
}.bind(this),
|
||||
);
|
||||
try {
|
||||
if (!socket_id || !producerTransportId || !rtpParameters || !kind || !type) {
|
||||
throw new Error('Invalid input parameters');
|
||||
}
|
||||
|
||||
const producer = await this.peers
|
||||
.get(socket_id)
|
||||
?.createProducer(producerTransportId, rtpParameters, kind, type);
|
||||
if (!producer) {
|
||||
throw new Error('Failed to create producer');
|
||||
}
|
||||
|
||||
const peer = this.peers.get(socket_id);
|
||||
const peerName = peer?.peer_name;
|
||||
const peerInfo = peer?.peer_info;
|
||||
|
||||
this.broadCast(socket_id, 'newProducers', [
|
||||
{
|
||||
producer_id: producer.id,
|
||||
producer_socket_id: socket_id,
|
||||
peer_name: peerName,
|
||||
peer_info: peerInfo,
|
||||
type: type,
|
||||
},
|
||||
]);
|
||||
|
||||
return producer.id;
|
||||
} catch (error) {
|
||||
console.error('Error producing', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// ####################################################
|
||||
@@ -289,45 +328,65 @@ module.exports = class Room {
|
||||
// ####################################################
|
||||
|
||||
async consume(socket_id, consumer_transport_id, producer_id, rtpCapabilities) {
|
||||
if (
|
||||
!this.router.canConsume({
|
||||
producerId: producer_id,
|
||||
rtpCapabilities,
|
||||
})
|
||||
) {
|
||||
return log.warn('Can not consume', {
|
||||
socket_id: socket_id,
|
||||
consumer_transport_id: consumer_transport_id,
|
||||
producer_id: producer_id,
|
||||
});
|
||||
}
|
||||
try {
|
||||
if (!socket_id || !consumer_transport_id || !producer_id || !rtpCapabilities) {
|
||||
throw new Error('Invalid input parameters');
|
||||
}
|
||||
|
||||
let { consumer, params } = await this.peers
|
||||
.get(socket_id)
|
||||
.createConsumer(consumer_transport_id, producer_id, rtpCapabilities);
|
||||
if (!this.router.canConsume({ producerId: producer_id, rtpCapabilities })) {
|
||||
log.warn('Cannot consume', {
|
||||
socket_id,
|
||||
consumer_transport_id,
|
||||
producer_id,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
consumer.on(
|
||||
'producerclose',
|
||||
function () {
|
||||
const peer = this.peers.get(socket_id);
|
||||
if (!peer) {
|
||||
log.warn('Peer not found for socket ID:', socket_id);
|
||||
return;
|
||||
}
|
||||
|
||||
const result = await peer.createConsumer(consumer_transport_id, producer_id, rtpCapabilities);
|
||||
|
||||
if (!result || !result.consumer || !result.params) {
|
||||
log.error('Consumer or params are not defined in createConsumer result');
|
||||
return;
|
||||
}
|
||||
|
||||
const { consumer, params } = result;
|
||||
|
||||
consumer.on('producerclose', () => {
|
||||
log.debug('Consumer closed due to producerclose event', {
|
||||
peer_name: this.peers.get(socket_id)?.peer_name,
|
||||
consumer_id: consumer.id,
|
||||
});
|
||||
this.peers.get(socket_id).removeConsumer(consumer.id);
|
||||
this.peers.get(socket_id)?.removeConsumer(consumer.id);
|
||||
|
||||
// tell client consumer is dead
|
||||
// Tell client consumer is dead
|
||||
this.io.to(socket_id).emit('consumerClosed', {
|
||||
consumer_id: consumer.id,
|
||||
consumer_kind: consumer.kind,
|
||||
});
|
||||
}.bind(this),
|
||||
);
|
||||
});
|
||||
|
||||
return params;
|
||||
return params;
|
||||
} catch (error) {
|
||||
log.error('Error occurred during consumption', error.message);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
closeProducer(socket_id, producer_id) {
|
||||
this.peers.get(socket_id).closeProducer(producer_id);
|
||||
try {
|
||||
if (!socket_id || !producer_id || !this.peers.has(socket_id)) {
|
||||
throw new Error('Invalid socket ID or producer ID');
|
||||
}
|
||||
this.peers.get(socket_id).closeProducer(producer_id);
|
||||
} catch (error) {
|
||||
log.error('Error closing producer:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// ####################################################
|
||||
|
||||
@@ -41,7 +41,7 @@ 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.3.80
|
||||
* @version 1.3.85
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -801,7 +801,7 @@ function startServer() {
|
||||
callback({ error: 'already exists' });
|
||||
} else {
|
||||
log.debug('Created room', { room_id: socket.room_id });
|
||||
let worker = await getMediasoupWorker();
|
||||
const worker = await getMediasoupWorker();
|
||||
roomList.set(socket.room_id, new Room(socket.room_id, worker, io));
|
||||
callback({ room_id: socket.room_id });
|
||||
}
|
||||
@@ -1313,7 +1313,7 @@ function startServer() {
|
||||
log.debug('Get producers', getPeerName(room));
|
||||
|
||||
// send all the current producer to newly joined member
|
||||
let producerList = room.getProducerListForPeer();
|
||||
const producerList = room.getProducerListForPeer();
|
||||
|
||||
socket.emit('newProducers', producerList);
|
||||
});
|
||||
@@ -1330,7 +1330,7 @@ function startServer() {
|
||||
const { params } = await room.createWebRtcTransport(socket.id);
|
||||
callback(params);
|
||||
} catch (err) {
|
||||
log.error('Create WebRtc Transport error: ', err.message);
|
||||
log.error('Create WebRtc Transport error', err.message);
|
||||
callback({
|
||||
error: err.message,
|
||||
});
|
||||
@@ -1358,10 +1358,10 @@ function startServer() {
|
||||
|
||||
const room = roomList.get(socket.room_id);
|
||||
|
||||
let peer_name = getPeerName(room, false);
|
||||
const peer_name = getPeerName(room, false);
|
||||
|
||||
// peer_info audio Or video ON
|
||||
let data = {
|
||||
const data = {
|
||||
peer_name: peer_name,
|
||||
peer_id: socket.id,
|
||||
kind: kind,
|
||||
@@ -1371,7 +1371,7 @@ function startServer() {
|
||||
|
||||
await room.getPeers().get(socket.id).updatePeerInfo(data);
|
||||
|
||||
let producer_id = await room.produce(
|
||||
const producer_id = await room.produce(
|
||||
socket.id,
|
||||
producerTransportId,
|
||||
rtpParameters,
|
||||
@@ -1404,7 +1404,7 @@ function startServer() {
|
||||
|
||||
const room = roomList.get(socket.room_id);
|
||||
|
||||
let params = await room.consume(socket.id, consumerTransportId, producerId, rtpCapabilities);
|
||||
const params = await room.consume(socket.id, consumerTransportId, producerId, rtpCapabilities);
|
||||
|
||||
log.debug('Consuming', {
|
||||
peer_name: getPeerName(room, false),
|
||||
@@ -1446,7 +1446,7 @@ function startServer() {
|
||||
|
||||
const room = roomList.get(socket.room_id);
|
||||
|
||||
let data = {
|
||||
const data = {
|
||||
room_id: socket.room_id,
|
||||
peer_counts: room.getPeers().size,
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "mirotalksfu",
|
||||
"version": "1.3.80",
|
||||
"version": "1.3.85",
|
||||
"description": "WebRTC SFU browser-based video calls",
|
||||
"main": "Server.js",
|
||||
"scripts": {
|
||||
@@ -53,7 +53,7 @@
|
||||
"mediasoup-client": "3.7.6",
|
||||
"ngrok": "^5.0.0-beta.2",
|
||||
"openai": "^4.28.4",
|
||||
"qs": "6.11.2",
|
||||
"qs": "6.12.0",
|
||||
"socket.io": "4.7.4",
|
||||
"swagger-ui-express": "5.0.0",
|
||||
"uuid": "9.0.1",
|
||||
|
||||
@@ -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.3.80
|
||||
* @version 1.3.85
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
تم حذف اختلاف الملف لأن الملف كبير جداً
تحميل الاختلاف
المرجع في مشكلة جديدة
حظر مستخدم