[mirotalksfu] - refactoring
هذا الالتزام موجود في:
@@ -133,7 +133,7 @@ definitions:
|
||||
timestamp:
|
||||
type: string
|
||||
format: date-time
|
||||
example: "2024-12-21T12:00:00Z"
|
||||
example: '2024-12-21T12:00:00Z'
|
||||
totalRooms:
|
||||
type: integer
|
||||
totalPeers:
|
||||
|
||||
@@ -108,25 +108,33 @@ module.exports = class Peer {
|
||||
|
||||
async connectTransport(transport_id, dtlsParameters) {
|
||||
if (!this.transports.has(transport_id)) {
|
||||
return false;
|
||||
throw new Error(`Transport with ID ${transport_id} not found`);
|
||||
}
|
||||
|
||||
await this.transports.get(transport_id).connect({
|
||||
dtlsParameters: dtlsParameters,
|
||||
});
|
||||
try {
|
||||
await this.transports.get(transport_id).connect({
|
||||
dtlsParameters: dtlsParameters,
|
||||
});
|
||||
} catch (error) {
|
||||
log.error(`Failed to connect transport with ID ${transport_id}`, error);
|
||||
throw new Error(`Failed to connect transport with ID ${transport_id}`);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
close() {
|
||||
this.transports.forEach((transport, transport_id) => {
|
||||
transport.close();
|
||||
this.delTransport(transport_id);
|
||||
log.debug('Closed and deleted peer transport', {
|
||||
//transport_id: transport_id,
|
||||
transportInternal: transport.internal,
|
||||
transport_closed: transport.closed,
|
||||
});
|
||||
try {
|
||||
transport.close();
|
||||
this.delTransport(transport_id);
|
||||
log.debug('Closed and deleted peer transport', {
|
||||
transportInternal: transport.internal,
|
||||
transport_closed: transport.closed,
|
||||
});
|
||||
} catch (error) {
|
||||
log.warn(`Error closing transport with ID ${transport_id}`, error.message);
|
||||
}
|
||||
});
|
||||
|
||||
const peerTransports = this.getTransports();
|
||||
@@ -159,14 +167,22 @@ module.exports = class Peer {
|
||||
}
|
||||
|
||||
async createProducer(producerTransportId, producer_rtpParameters, producer_kind, producer_type) {
|
||||
if (!this.transports.has(producerTransportId)) return;
|
||||
if (!this.transports.has(producerTransportId)) {
|
||||
throw new Error(`Producer transport with ID ${producerTransportId} not found`);
|
||||
}
|
||||
|
||||
const producerTransport = this.transports.get(producerTransportId);
|
||||
|
||||
const producer = await producerTransport.produce({
|
||||
kind: producer_kind,
|
||||
rtpParameters: producer_rtpParameters,
|
||||
});
|
||||
let producer;
|
||||
try {
|
||||
producer = await producerTransport.produce({
|
||||
kind: producer_kind,
|
||||
rtpParameters: producer_rtpParameters,
|
||||
});
|
||||
} catch (error) {
|
||||
log.error(`Error creating producer for transport ID ${producerTransportId}:`, error);
|
||||
throw new Error(`Failed to create producer for transport ID ${producerTransportId}`);
|
||||
}
|
||||
|
||||
const { id, appData, type, kind, rtpParameters } = producer;
|
||||
|
||||
@@ -236,17 +252,25 @@ module.exports = class Peer {
|
||||
}
|
||||
|
||||
async createConsumer(consumer_transport_id, producer_id, rtpCapabilities) {
|
||||
if (!this.transports.has(consumer_transport_id)) return;
|
||||
if (!this.transports.has(consumer_transport_id)) {
|
||||
throw new Error(`Consumer transport with ID ${consumer_transport_id} not found`);
|
||||
}
|
||||
|
||||
const consumerTransport = this.transports.get(consumer_transport_id);
|
||||
|
||||
const consumer = await consumerTransport.consume({
|
||||
producerId: producer_id,
|
||||
rtpCapabilities,
|
||||
enableRtx: true, // Enable NACK for OPUS.
|
||||
paused: true,
|
||||
ignoreDtx: true,
|
||||
});
|
||||
let consumer;
|
||||
try {
|
||||
consumer = await consumerTransport.consume({
|
||||
producerId: producer_id,
|
||||
rtpCapabilities,
|
||||
enableRtx: true, // Enable NACK for OPUS.
|
||||
paused: true,
|
||||
ignoreDtx: true,
|
||||
});
|
||||
} catch (error) {
|
||||
log.error(`Error creating consumer for transport ID ${consumer_transport_id}`, error);
|
||||
throw new Error(`Failed to create consumer for transport ID ${consumer_transport_id}`);
|
||||
}
|
||||
|
||||
const { id, type, kind, rtpParameters, producerPaused } = consumer;
|
||||
|
||||
|
||||
@@ -532,7 +532,9 @@ module.exports = class Room {
|
||||
// ####################################################
|
||||
|
||||
async createWebRtcTransport(socket_id) {
|
||||
if (!this.peers.has(socket_id)) return;
|
||||
if (!this.peers.has(socket_id)) {
|
||||
throw new Error(`Peer with socket ID ${socket_id} not found in the room`);
|
||||
}
|
||||
|
||||
const { maxIncomingBitrate, initialAvailableOutgoingBitrate, listenInfos } = this.webRtcTransport;
|
||||
|
||||
@@ -550,7 +552,7 @@ module.exports = class Room {
|
||||
const transport = await this.router.createWebRtcTransport(webRtcTransportOptions);
|
||||
|
||||
if (!transport) {
|
||||
throw new Error('Create WebRtc Transport failed!');
|
||||
throw new Error('Failed to create WebRtc Transport');
|
||||
}
|
||||
|
||||
const { id, type, iceParameters, iceCandidates, dtlsParameters } = transport;
|
||||
@@ -558,7 +560,10 @@ module.exports = class Room {
|
||||
if (maxIncomingBitrate) {
|
||||
try {
|
||||
await transport.setMaxIncomingBitrate(maxIncomingBitrate);
|
||||
} catch (error) {}
|
||||
} catch (error) {
|
||||
log.error('Failed to set max incoming bitrate', error);
|
||||
throw new Error(`Failed to set max incoming bitrate for transport ${id}`);
|
||||
}
|
||||
}
|
||||
|
||||
const peer = this.getPeer(socket_id);
|
||||
@@ -615,11 +620,18 @@ module.exports = class Room {
|
||||
}
|
||||
|
||||
async connectPeerTransport(socket_id, transport_id, dtlsParameters) {
|
||||
if (!this.peers.has(socket_id)) return;
|
||||
if (!this.peers.has(socket_id)) {
|
||||
throw new Error(`Peer with socket ID ${socket_id} not found in the room`);
|
||||
}
|
||||
|
||||
const peer = this.getPeer(socket_id);
|
||||
|
||||
await peer.connectTransport(transport_id, dtlsParameters);
|
||||
try {
|
||||
await peer.connectTransport(transport_id, dtlsParameters);
|
||||
} catch (error) {
|
||||
log.error(`Failed to connect peer transport for socket ID ${socket_id}`, error);
|
||||
throw new Error(`Failed to connect transport for peer with socket ID ${socket_id}`);
|
||||
}
|
||||
|
||||
return '[Room|connectPeerTransport] done';
|
||||
}
|
||||
@@ -629,14 +641,22 @@ module.exports = class Room {
|
||||
// ####################################################
|
||||
|
||||
async produce(socket_id, producerTransportId, rtpParameters, kind, type) {
|
||||
if (!this.peers.has(socket_id)) return;
|
||||
if (!this.peers.has(socket_id)) {
|
||||
throw new Error(`Peer with socket ID ${socket_id} not found in the room`);
|
||||
}
|
||||
|
||||
const peer = this.getPeer(socket_id);
|
||||
|
||||
const peerProducer = await peer.createProducer(producerTransportId, rtpParameters, kind, type);
|
||||
let peerProducer;
|
||||
try {
|
||||
peerProducer = await peer.createProducer(producerTransportId, rtpParameters, kind, type);
|
||||
} catch (error) {
|
||||
log.error(`Error creating producer for peer with socket ID ${socket_id}`, error);
|
||||
throw new Error(`Error creating producer with transport ID ${producerTransportId} for peer ${socket_id}`);
|
||||
}
|
||||
|
||||
if (!peerProducer) {
|
||||
throw new Error(`Peer producer kind ${kind} with id ${producerTransportId} not found`);
|
||||
throw new Error(`Failed to create producer with ID ${producerTransportId} for peer ${socket_id}`);
|
||||
}
|
||||
|
||||
const { id } = peerProducer;
|
||||
@@ -657,11 +677,18 @@ module.exports = class Room {
|
||||
}
|
||||
|
||||
closeProducer(socket_id, producer_id) {
|
||||
if (!this.peers.has(socket_id)) return;
|
||||
if (!this.peers.has(socket_id)) {
|
||||
throw new Error(`Peer with socket ID ${socket_id} not found in the room`);
|
||||
}
|
||||
|
||||
const peer = this.getPeer(socket_id);
|
||||
|
||||
peer.closeProducer(producer_id);
|
||||
try {
|
||||
peer.closeProducer(producer_id);
|
||||
} catch (error) {
|
||||
log.error(`Error closing producer for peer ${socket_id}`, error);
|
||||
throw new Error(`Error closing producer with ID ${producer_id} for peer ${socket_id}`);
|
||||
}
|
||||
}
|
||||
|
||||
// ####################################################
|
||||
@@ -669,28 +696,30 @@ module.exports = class Room {
|
||||
// ####################################################
|
||||
|
||||
async consume(socket_id, consumer_transport_id, producer_id, rtpCapabilities) {
|
||||
if (!this.peers.has(socket_id)) return;
|
||||
if (!this.peers.has(socket_id)) {
|
||||
throw new Error(`Peer with socket ID ${socket_id} not found in the room`);
|
||||
}
|
||||
|
||||
if (
|
||||
!this.router.canConsume({
|
||||
producerId: producer_id,
|
||||
rtpCapabilities,
|
||||
})
|
||||
) {
|
||||
log.warn('Cannot consume', {
|
||||
socket_id,
|
||||
consumer_transport_id,
|
||||
producer_id,
|
||||
});
|
||||
return;
|
||||
if (!this.router.canConsume({ producerId: producer_id, rtpCapabilities })) {
|
||||
throw new Error(`Cannot consume producer with ID ${producer_id}, router validation failed`);
|
||||
}
|
||||
|
||||
const peer = this.getPeer(socket_id);
|
||||
|
||||
const peerConsumer = await peer.createConsumer(consumer_transport_id, producer_id, rtpCapabilities);
|
||||
let peerConsumer;
|
||||
try {
|
||||
peerConsumer = await peer.createConsumer(consumer_transport_id, producer_id, rtpCapabilities);
|
||||
} catch (error) {
|
||||
log.error(`Error creating consumer for peer with socket ID ${socket_id}`, error);
|
||||
throw new Error(
|
||||
`Failed to create consumer with transport ID ${consumer_transport_id} and producer ID ${producer_id} for peer ${socket_id}`,
|
||||
);
|
||||
}
|
||||
|
||||
if (!peerConsumer) {
|
||||
throw new Error(`Peer consumer kind ${kind} with id ${consumer_transport_id} not found`);
|
||||
throw new Error(
|
||||
`Consumer creation failed for transport ID ${consumer_transport_id} and producer ID ${producer_id}`,
|
||||
);
|
||||
}
|
||||
|
||||
const { consumer, params } = peerConsumer;
|
||||
@@ -702,7 +731,7 @@ module.exports = class Room {
|
||||
|
||||
peer.removeConsumer(id);
|
||||
|
||||
// Notify the client that consumer is closed
|
||||
// Notify the client that the consumer is closed
|
||||
this.send(socket_id, 'consumerClosed', {
|
||||
consumer_id: id,
|
||||
consumer_kind: kind,
|
||||
|
||||
@@ -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.6.55
|
||||
* @version 1.6.60
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -1558,15 +1558,10 @@ function startServer() {
|
||||
|
||||
try {
|
||||
const createWebRtcTransport = await room.createWebRtcTransport(socket.id);
|
||||
|
||||
//log.debug('Create WebRtc transport callback', { callback: createWebRtcTransport });
|
||||
|
||||
callback(createWebRtcTransport);
|
||||
} catch (err) {
|
||||
log.error('Create WebRtc Transport error', err);
|
||||
callback({
|
||||
error: err.message,
|
||||
});
|
||||
callback({ error: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1576,22 +1571,16 @@ function startServer() {
|
||||
}
|
||||
|
||||
const { room, peer } = getRoomAndPeer(socket);
|
||||
|
||||
const { peer_name } = peer || 'undefined';
|
||||
|
||||
log.debug('Connect transport', { peer_name: peer_name, transport_id: transport_id });
|
||||
|
||||
try {
|
||||
const connectTransport = await room.connectPeerTransport(socket.id, transport_id, dtlsParameters);
|
||||
|
||||
//log.debug('Connect transport', { callback: connectTransport });
|
||||
|
||||
callback(connectTransport);
|
||||
callback({ success: true, message: connectTransport });
|
||||
} catch (err) {
|
||||
log.error('Connect transport error', err);
|
||||
callback({
|
||||
error: err.message,
|
||||
});
|
||||
callback({ success: false, error: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1624,9 +1613,7 @@ function startServer() {
|
||||
callback(iceParameters);
|
||||
} catch (err) {
|
||||
log.error('Restart ICE error', err);
|
||||
callback({
|
||||
error: err.message,
|
||||
});
|
||||
callback({ error: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1643,7 +1630,6 @@ function startServer() {
|
||||
|
||||
const { peer_name } = peer || 'undefined';
|
||||
|
||||
// peer_info.audio OR video ON
|
||||
const data = {
|
||||
room_id: room.id,
|
||||
peer_name: peer_name,
|
||||
@@ -1678,16 +1664,10 @@ function startServer() {
|
||||
room.addProducerToActiveSpeakerObserver({ producerId: producer_id });
|
||||
}
|
||||
|
||||
//log.debug('Producer transport callback', { callback: producer_id });
|
||||
|
||||
callback({
|
||||
producer_id,
|
||||
});
|
||||
callback({ producer_id });
|
||||
} catch (err) {
|
||||
log.error('Producer transport error', err);
|
||||
callback({
|
||||
error: err.message,
|
||||
});
|
||||
callback({ error: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1709,14 +1689,10 @@ function startServer() {
|
||||
consumer_id: params ? params.id : undefined,
|
||||
});
|
||||
|
||||
//log.debug('Consumer transport callback', { callback: params });
|
||||
|
||||
callback(params);
|
||||
} catch (err) {
|
||||
log.error('Consumer transport error', err);
|
||||
callback({
|
||||
error: err.message,
|
||||
});
|
||||
callback({ error: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1751,15 +1727,15 @@ function startServer() {
|
||||
|
||||
try {
|
||||
await producer.pause();
|
||||
|
||||
const { peer_name } = peer || 'undefined';
|
||||
|
||||
log.debug('Producer paused', { peer_name: peer_name, producer_id: producer_id });
|
||||
|
||||
callback('successfully');
|
||||
} catch (error) {
|
||||
return callback({ error: error.message });
|
||||
callback({ error: error.message });
|
||||
}
|
||||
|
||||
const { peer_name } = peer || 'undefined';
|
||||
|
||||
log.debug('Producer paused', { peer_name: peer_name, producer_id: producer_id });
|
||||
|
||||
callback('successfully');
|
||||
});
|
||||
|
||||
socket.on('resumeProducer', async ({ producer_id }, callback) => {
|
||||
@@ -1781,15 +1757,15 @@ function startServer() {
|
||||
|
||||
try {
|
||||
await producer.resume();
|
||||
|
||||
const { peer_name } = peer || 'undefined';
|
||||
|
||||
log.debug('Producer resumed', { peer_name: peer_name, producer_id: producer_id });
|
||||
|
||||
callback('successfully');
|
||||
} catch (error) {
|
||||
return callback({ error: error.message });
|
||||
callback({ error: error.message });
|
||||
}
|
||||
|
||||
const { peer_name } = peer || 'undefined';
|
||||
|
||||
log.debug('Producer resumed', { peer_name: peer_name, producer_id: producer_id });
|
||||
|
||||
callback('successfully');
|
||||
});
|
||||
|
||||
socket.on('resumeConsumer', async ({ consumer_id }, callback) => {
|
||||
@@ -1811,15 +1787,15 @@ function startServer() {
|
||||
|
||||
try {
|
||||
await consumer.resume();
|
||||
|
||||
const { peer_name } = peer || 'undefined';
|
||||
|
||||
log.debug('Consumer resumed', { peer_name: peer_name, consumer_id: consumer_id });
|
||||
|
||||
callback('successfully');
|
||||
} catch (error) {
|
||||
return callback({ error: error.message });
|
||||
callback({ error: error.message });
|
||||
}
|
||||
|
||||
const { peer_name } = peer || 'undefined';
|
||||
|
||||
log.debug('Consumer resumed', { peer_name: peer_name, consumer_id: consumer_id });
|
||||
|
||||
callback('successfully');
|
||||
});
|
||||
|
||||
socket.on('getProducers', () => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "mirotalksfu",
|
||||
"version": "1.6.55",
|
||||
"version": "1.6.60",
|
||||
"description": "WebRTC SFU browser-based video calls",
|
||||
"main": "Server.js",
|
||||
"scripts": {
|
||||
|
||||
@@ -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.6.55
|
||||
* @version 1.6.60
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -4619,7 +4619,7 @@ function showAbout() {
|
||||
imageUrl: image.about,
|
||||
customClass: { image: 'img-about' },
|
||||
position: 'center',
|
||||
title: 'WebRTC SFU v1.6.55',
|
||||
title: 'WebRTC SFU v1.6.60',
|
||||
html: `
|
||||
<br />
|
||||
<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 CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970
|
||||
* @author Miroslav Pejic - miroslav.pejic.85@gmail.com
|
||||
* @version 1.6.55
|
||||
* @version 1.6.60
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -688,12 +688,17 @@ class RoomClient {
|
||||
|
||||
this.producerTransport.on('connect', async ({ dtlsParameters }, callback, errback) => {
|
||||
try {
|
||||
await this.socket.request('connectTransport', {
|
||||
const response = await this.socket.request('connectTransport', {
|
||||
transport_id: this.producerTransport.id,
|
||||
dtlsParameters,
|
||||
});
|
||||
if (!response.success) {
|
||||
console.error('Producer Transport connection failed', response.error);
|
||||
throw new Error(response.error);
|
||||
}
|
||||
callback();
|
||||
} catch (err) {
|
||||
console.error('Producer Transport connection error', err);
|
||||
errback(err);
|
||||
}
|
||||
});
|
||||
@@ -792,12 +797,17 @@ class RoomClient {
|
||||
|
||||
this.consumerTransport.on('connect', async ({ dtlsParameters }, callback, errback) => {
|
||||
try {
|
||||
await this.socket.request('connectTransport', {
|
||||
const response = await this.socket.request('connectTransport', {
|
||||
transport_id: this.consumerTransport.id,
|
||||
dtlsParameters,
|
||||
});
|
||||
if (!response.success) {
|
||||
console.error('Consumer Transport connection failed', response.error);
|
||||
throw new Error(response.error);
|
||||
}
|
||||
callback();
|
||||
} catch (err) {
|
||||
console.error('Consumer Transport connection error', err);
|
||||
errback(err);
|
||||
}
|
||||
});
|
||||
@@ -2272,13 +2282,24 @@ class RoomClient {
|
||||
async getConsumeStream(producerId, peer_id, type) {
|
||||
const { rtpCapabilities } = this.device;
|
||||
|
||||
const data = await this.socket.request('consume', {
|
||||
rtpCapabilities,
|
||||
consumerTransportId: this.consumerTransport.id,
|
||||
producerId,
|
||||
});
|
||||
let data = {};
|
||||
|
||||
console.log('DATA', data);
|
||||
try {
|
||||
data = await this.socket.request('consume', {
|
||||
rtpCapabilities,
|
||||
consumerTransportId: this.consumerTransport.id,
|
||||
producerId,
|
||||
});
|
||||
|
||||
if (data.error) {
|
||||
console.error('Error consuming producer:', data.error);
|
||||
throw new Error(data.error);
|
||||
}
|
||||
|
||||
console.log('Consumer parameters received:', data);
|
||||
} catch (err) {
|
||||
console.error('Failed to consume:', err);
|
||||
}
|
||||
|
||||
const { id, kind, rtpParameters } = data;
|
||||
const codecOptions = {};
|
||||
|
||||
المرجع في مشكلة جديدة
حظر مستخدم