[mirotalksfu] - refactoring
هذا الالتزام موجود في:
@@ -98,12 +98,12 @@ module.exports = class Peer {
|
|||||||
async createProducer(producerTransportId, producer_rtpParameters, producer_kind, producer_type) {
|
async createProducer(producerTransportId, producer_rtpParameters, producer_kind, producer_type) {
|
||||||
try {
|
try {
|
||||||
if (!producerTransportId) {
|
if (!producerTransportId) {
|
||||||
throw new Error('Invalid producer transport ID');
|
return 'Invalid producer transport ID';
|
||||||
}
|
}
|
||||||
|
|
||||||
const producerTransport = this.transports.get(producerTransportId);
|
const producerTransport = this.transports.get(producerTransportId);
|
||||||
if (!producerTransport) {
|
if (!producerTransport) {
|
||||||
throw new Error(`Producer transport with ID ${producerTransportId} not found`);
|
return `Producer transport with ID ${producerTransportId} not found`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const producer = await producerTransport.produce({
|
const producer = await producerTransport.produce({
|
||||||
@@ -112,7 +112,7 @@ module.exports = class Peer {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (!producer) {
|
if (!producer) {
|
||||||
throw new Error(`Producer type: ${producer_type} kind: ${producer_kind} not found`);
|
return `Producer type: ${producer_type} kind: ${producer_kind} not found`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { id, appData, type, kind, rtpParameters } = producer;
|
const { id, appData, type, kind, rtpParameters } = producer;
|
||||||
@@ -145,7 +145,7 @@ module.exports = class Peer {
|
|||||||
return producer;
|
return producer;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
log.error('Error creating producer', error.message);
|
log.error('Error creating producer', error.message);
|
||||||
return null;
|
return error.message;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,8 +153,8 @@ module.exports = class Peer {
|
|||||||
if (!this.producers.has(producer_id)) return;
|
if (!this.producers.has(producer_id)) return;
|
||||||
try {
|
try {
|
||||||
this.producers.get(producer_id).close();
|
this.producers.get(producer_id).close();
|
||||||
} catch (ex) {
|
} catch (error) {
|
||||||
log.warn('Close Producer', ex);
|
log.warn('Close Producer', error.message);
|
||||||
}
|
}
|
||||||
this.producers.delete(producer_id);
|
this.producers.delete(producer_id);
|
||||||
}
|
}
|
||||||
@@ -168,7 +168,7 @@ module.exports = class Peer {
|
|||||||
const consumerTransport = this.transports.get(consumer_transport_id);
|
const consumerTransport = this.transports.get(consumer_transport_id);
|
||||||
|
|
||||||
if (!consumerTransport) {
|
if (!consumerTransport) {
|
||||||
throw new Error(`Consumer transport with id ${consumer_transport_id} not found`);
|
return `Consumer transport with id ${consumer_transport_id} not found`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const consumer = await consumerTransport.consume({
|
const consumer = await consumerTransport.consume({
|
||||||
@@ -179,7 +179,7 @@ module.exports = class Peer {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (!consumer) {
|
if (!consumer) {
|
||||||
throw new Error(`Consumer for producer ID ${producer_id} not found`);
|
return `Consumer for producer ID ${producer_id} not found`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { id, type, kind, rtpParameters, producerPaused } = consumer;
|
const { id, type, kind, rtpParameters, producerPaused } = consumer;
|
||||||
@@ -224,7 +224,7 @@ module.exports = class Peer {
|
|||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
log.error('Error creating consumer', error.message);
|
log.error('Error creating consumer', error.message);
|
||||||
return null;
|
return error.message;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
273
app/src/Room.js
273
app/src/Room.js
@@ -216,22 +216,6 @@ module.exports = class Room {
|
|||||||
return producerList;
|
return producerList;
|
||||||
}
|
}
|
||||||
|
|
||||||
async connectPeerTransport(socket_id, 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.message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async removePeer(socket_id) {
|
async removePeer(socket_id) {
|
||||||
if (!this.peers.has(socket_id)) return;
|
if (!this.peers.has(socket_id)) return;
|
||||||
this.peers.get(socket_id).close();
|
this.peers.get(socket_id).close();
|
||||||
@@ -243,92 +227,103 @@ module.exports = class Room {
|
|||||||
// ####################################################
|
// ####################################################
|
||||||
|
|
||||||
async createWebRtcTransport(socket_id) {
|
async createWebRtcTransport(socket_id) {
|
||||||
try {
|
if (!this.peers.has(socket_id)) {
|
||||||
if (!socket_id || !this.peers.has(socket_id)) {
|
return this.printError(`[Room|createWebRtcTransport] Invalid socket ID: ${socket_id}`);
|
||||||
throw new Error(`Invalid socket ID: ${socket_id}`);
|
}
|
||||||
|
|
||||||
|
const { maxIncomingBitrate, initialAvailableOutgoingBitrate, listenInfos } = this.webRtcTransport;
|
||||||
|
|
||||||
|
const webRtcTransportOptions = {
|
||||||
|
...(this.webRtcServerActive ? { webRtcServer: this.webRtcServer } : { listenInfos }),
|
||||||
|
enableUdp: true,
|
||||||
|
enableTcp: true,
|
||||||
|
preferUdp: true,
|
||||||
|
iceConsentTimeout: 20,
|
||||||
|
initialAvailableOutgoingBitrate,
|
||||||
|
};
|
||||||
|
|
||||||
|
const transport = await this.router.createWebRtcTransport(webRtcTransportOptions);
|
||||||
|
|
||||||
|
if (!transport) {
|
||||||
|
return this.printError('[Room|createWebRtcTransport] Failed to create WebRTC transport');
|
||||||
|
}
|
||||||
|
|
||||||
|
const { id, iceParameters, iceCandidates, dtlsParameters } = transport;
|
||||||
|
|
||||||
|
if (maxIncomingBitrate) {
|
||||||
|
try {
|
||||||
|
await transport.setMaxIncomingBitrate(maxIncomingBitrate);
|
||||||
|
} catch (error) {
|
||||||
|
log.debug('Transport setMaxIncomingBitrate error', error.message);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const { maxIncomingBitrate, initialAvailableOutgoingBitrate, listenInfos } = this.webRtcTransport;
|
const peer = this.peers.get(socket_id);
|
||||||
|
|
||||||
const webRtcTransportOptions = {
|
const { peer_name } = peer;
|
||||||
...(this.webRtcServerActive ? { webRtcServer: this.webRtcServer } : { listenInfos }),
|
|
||||||
enableUdp: true,
|
|
||||||
enableTcp: true,
|
|
||||||
preferUdp: true,
|
|
||||||
iceConsentTimeout: 20,
|
|
||||||
initialAvailableOutgoingBitrate,
|
|
||||||
};
|
|
||||||
|
|
||||||
const transport = await this.router.createWebRtcTransport(webRtcTransportOptions);
|
transport.on('icestatechange', (iceState) => {
|
||||||
|
if (iceState === 'disconnected' || iceState === 'closed') {
|
||||||
if (!transport) {
|
log.debug('Transport closed "icestatechange" event', {
|
||||||
throw new Error('Failed to create WebRTC transport');
|
|
||||||
}
|
|
||||||
|
|
||||||
const { id, iceParameters, iceCandidates, dtlsParameters } = transport;
|
|
||||||
|
|
||||||
if (maxIncomingBitrate) {
|
|
||||||
try {
|
|
||||||
await transport.setMaxIncomingBitrate(maxIncomingBitrate);
|
|
||||||
} catch (error) {
|
|
||||||
log.debug('Transport setMaxIncomingBitrate error', error.message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const peer = this.peers.get(socket_id);
|
|
||||||
|
|
||||||
const { peer_name } = peer;
|
|
||||||
|
|
||||||
transport.on('icestatechange', (iceState) => {
|
|
||||||
if (iceState === 'disconnected' || iceState === 'closed') {
|
|
||||||
log.debug('Transport closed "icestatechange" event', {
|
|
||||||
peer_name: peer_name,
|
|
||||||
iceState: iceState,
|
|
||||||
});
|
|
||||||
transport.close();
|
|
||||||
//this.router.close();
|
|
||||||
//peer.close();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
transport.on('sctpstatechange', (sctpState) => {
|
|
||||||
log.debug('Transport "sctpstatechange" event', {
|
|
||||||
peer_name: peer_name,
|
peer_name: peer_name,
|
||||||
sctpState: sctpState,
|
iceState: iceState,
|
||||||
});
|
});
|
||||||
|
transport.close();
|
||||||
|
//this.router.close();
|
||||||
|
//peer.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
transport.on('sctpstatechange', (sctpState) => {
|
||||||
|
log.debug('Transport "sctpstatechange" event', {
|
||||||
|
peer_name: peer_name,
|
||||||
|
sctpState: sctpState,
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
transport.on('dtlsstatechange', (dtlsState) => {
|
transport.on('dtlsstatechange', (dtlsState) => {
|
||||||
if (dtlsState === 'failed' || dtlsState === 'closed') {
|
if (dtlsState === 'failed' || dtlsState === 'closed') {
|
||||||
log.debug('Transport closed "dtlsstatechange" event', {
|
log.debug('Transport closed "dtlsstatechange" event', {
|
||||||
peer_name: peer_name,
|
peer_name: peer_name,
|
||||||
dtlsState: dtlsState,
|
dtlsState: dtlsState,
|
||||||
});
|
});
|
||||||
transport.close();
|
transport.close();
|
||||||
//this.router.close();
|
//this.router.close();
|
||||||
//peer.close();
|
//peer.close();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
transport.on('close', () => {
|
transport.on('close', () => {
|
||||||
log.debug('Transport closed', { peer_name: peer_name });
|
log.debug('Transport closed', { peer_name: peer_name });
|
||||||
});
|
});
|
||||||
|
|
||||||
log.debug('Adding transport', { transportId: id });
|
log.debug('Adding transport', { transportId: id });
|
||||||
|
|
||||||
peer.addTransport(transport);
|
peer.addTransport(transport);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
params: {
|
id: id,
|
||||||
id: id,
|
iceParameters: iceParameters,
|
||||||
iceParameters: iceParameters,
|
iceCandidates: iceCandidates,
|
||||||
iceCandidates: iceCandidates,
|
dtlsParameters: dtlsParameters,
|
||||||
dtlsParameters: dtlsParameters,
|
};
|
||||||
},
|
}
|
||||||
};
|
|
||||||
|
async connectPeerTransport(socket_id, transport_id, dtlsParameters) {
|
||||||
|
try {
|
||||||
|
if (!socket_id || !transport_id || !dtlsParameters) {
|
||||||
|
return this.printError('[Room|connectPeerTransport] Invalid input parameters');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.peers.has(socket_id)) {
|
||||||
|
return this.printError(`[Room|connectPeerTransport] Peer with socket ID ${socket_id} not found`);
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.peers.get(socket_id).connectTransport(transport_id, dtlsParameters);
|
||||||
|
return '[Room|connectPeerTransport] done';
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
log.error('Error creating WebRTC transport', error.message);
|
log.error('Error connecting peer transport', error.message);
|
||||||
return null;
|
return this.printError(`[Room|connectPeerTransport] error: ${error.message}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -337,41 +332,37 @@ module.exports = class Room {
|
|||||||
// ####################################################
|
// ####################################################
|
||||||
|
|
||||||
async produce(socket_id, producerTransportId, rtpParameters, kind, type) {
|
async produce(socket_id, producerTransportId, rtpParameters, kind, type) {
|
||||||
try {
|
//
|
||||||
if (!socket_id || !producerTransportId || !rtpParameters || !kind || !type) {
|
if (!socket_id || !producerTransportId || !rtpParameters || !kind || !type) {
|
||||||
throw new Error('Invalid input parameters');
|
return this.printError('[Room|produce] Invalid input parameters');
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.peers.has(socket_id)) {
|
|
||||||
throw new Error(`Invalid socket ID: ${socket_id}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const peer = this.peers.get(socket_id);
|
|
||||||
|
|
||||||
const producer = await peer.createProducer(producerTransportId, rtpParameters, kind, type);
|
|
||||||
if (!producer) {
|
|
||||||
throw new Error('Failed to create producer');
|
|
||||||
}
|
|
||||||
|
|
||||||
const { id } = producer;
|
|
||||||
|
|
||||||
const { peer_name, peer_info } = peer;
|
|
||||||
|
|
||||||
this.broadCast(socket_id, 'newProducers', [
|
|
||||||
{
|
|
||||||
producer_id: id,
|
|
||||||
producer_socket_id: socket_id,
|
|
||||||
peer_name: peer_name,
|
|
||||||
peer_info: peer_info,
|
|
||||||
type: type,
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
|
|
||||||
return id;
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error producing', error.message);
|
|
||||||
throw error.message;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!this.peers.has(socket_id)) {
|
||||||
|
return this.printError(`[Room|produce] Invalid socket ID: ${socket_id}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const peer = this.peers.get(socket_id);
|
||||||
|
|
||||||
|
const peerProducer = await peer.createProducer(producerTransportId, rtpParameters, kind, type);
|
||||||
|
if (!peerProducer || !peerProducer.id) {
|
||||||
|
return this.printError(`[Room|produce] peerProducer error: '${peerProducer}'`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const { id } = peerProducer;
|
||||||
|
|
||||||
|
const { peer_name, peer_info } = peer;
|
||||||
|
|
||||||
|
this.broadCast(socket_id, 'newProducers', [
|
||||||
|
{
|
||||||
|
producer_id: id,
|
||||||
|
producer_socket_id: socket_id,
|
||||||
|
peer_name: peer_name,
|
||||||
|
peer_info: peer_info,
|
||||||
|
type: type,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ####################################################
|
// ####################################################
|
||||||
@@ -381,7 +372,7 @@ module.exports = class Room {
|
|||||||
async consume(socket_id, consumer_transport_id, producer_id, rtpCapabilities) {
|
async consume(socket_id, consumer_transport_id, producer_id, rtpCapabilities) {
|
||||||
try {
|
try {
|
||||||
if (!socket_id || !consumer_transport_id || !producer_id || !rtpCapabilities) {
|
if (!socket_id || !consumer_transport_id || !producer_id || !rtpCapabilities) {
|
||||||
throw new Error('Invalid input parameters');
|
return this.printError('[Room|consume] Invalid input parameters');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.router.canConsume({ producerId: producer_id, rtpCapabilities })) {
|
if (!this.router.canConsume({ producerId: producer_id, rtpCapabilities })) {
|
||||||
@@ -390,26 +381,26 @@ module.exports = class Room {
|
|||||||
consumer_transport_id,
|
consumer_transport_id,
|
||||||
producer_id,
|
producer_id,
|
||||||
});
|
});
|
||||||
return;
|
return this.printError(`[Room|consume] Room router cannot consume producer_id: '${producer_id}'`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.peers.has(socket_id)) {
|
if (!this.peers.has(socket_id)) {
|
||||||
log.warn('Peer not found for socket ID', socket_id);
|
log.warn('Peer not found for socket ID', socket_id);
|
||||||
return;
|
return this.printError('[Room|consume] Peer not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
const peer = this.peers.get(socket_id);
|
const peer = this.peers.get(socket_id);
|
||||||
|
|
||||||
const { peer_name } = peer;
|
const { peer_name } = peer;
|
||||||
|
|
||||||
const result = await peer.createConsumer(consumer_transport_id, producer_id, rtpCapabilities);
|
const peerConsumer = await peer.createConsumer(consumer_transport_id, producer_id, rtpCapabilities);
|
||||||
|
|
||||||
if (!result || !result.consumer || !result.params) {
|
if (!peerConsumer || !peerConsumer.consumer || !peerConsumer.params) {
|
||||||
log.debug('Consumer or params are not defined in createConsumer result');
|
log.debug('peerConsumer or params are not defined');
|
||||||
return;
|
return this.printError(`[Room|consume] peerConsumer error: '${peerConsumer}'`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const { consumer, params } = result;
|
const { consumer, params } = peerConsumer;
|
||||||
|
|
||||||
const { id, kind } = consumer;
|
const { id, kind } = consumer;
|
||||||
|
|
||||||
@@ -430,19 +421,13 @@ module.exports = class Room {
|
|||||||
return params;
|
return params;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
log.error('Error occurred during consumption', error.message);
|
log.error('Error occurred during consumption', error.message);
|
||||||
return;
|
return this.printError(`[Room|consume] ${error.message}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
closeProducer(socket_id, producer_id) {
|
closeProducer(socket_id, producer_id) {
|
||||||
try {
|
if (!socket_id || !producer_id || !this.peers.has(socket_id)) return;
|
||||||
if (!socket_id || !producer_id || !this.peers.has(socket_id)) {
|
this.peers.get(socket_id).closeProducer(producer_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.message);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ####################################################
|
// ####################################################
|
||||||
@@ -499,6 +484,14 @@ module.exports = class Room {
|
|||||||
this._hostOnlyRecording = status;
|
this._hostOnlyRecording = status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ####################################################
|
||||||
|
// ERRORS
|
||||||
|
// ####################################################
|
||||||
|
|
||||||
|
printError(message) {
|
||||||
|
return { error: message };
|
||||||
|
}
|
||||||
|
|
||||||
// ####################################################
|
// ####################################################
|
||||||
// SENDER
|
// SENDER
|
||||||
// ####################################################
|
// ####################################################
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ 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.3.92
|
* @version 1.3.93
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -1001,8 +1001,8 @@ function startServer() {
|
|||||||
|
|
||||||
log.debug('Get RouterRtpCapabilities', getPeerName(room));
|
log.debug('Get RouterRtpCapabilities', getPeerName(room));
|
||||||
try {
|
try {
|
||||||
const routerRtpCapabilities = room.getRtpCapabilities();
|
const getRouterRtpCapabilities = room.getRtpCapabilities();
|
||||||
callback(routerRtpCapabilities);
|
callback(getRouterRtpCapabilities);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
log.error('Get RouterRtpCapabilities error', err.message);
|
log.error('Get RouterRtpCapabilities error', err.message);
|
||||||
callback({
|
callback({
|
||||||
@@ -1020,8 +1020,8 @@ function startServer() {
|
|||||||
|
|
||||||
log.debug('Create webrtc transport', getPeerName(room));
|
log.debug('Create webrtc transport', getPeerName(room));
|
||||||
try {
|
try {
|
||||||
const { params } = await room.createWebRtcTransport(socket.id);
|
const createWebRtcTransport = await room.createWebRtcTransport(socket.id);
|
||||||
callback(params);
|
callback(createWebRtcTransport);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
log.error('Create WebRtc Transport error', err.message);
|
log.error('Create WebRtc Transport error', err.message);
|
||||||
callback({
|
callback({
|
||||||
@@ -1042,8 +1042,8 @@ function startServer() {
|
|||||||
log.debug('Connect transport', { peer_name: peer_name, transport_id: transport_id });
|
log.debug('Connect transport', { peer_name: peer_name, transport_id: transport_id });
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await room.connectPeerTransport(socket.id, transport_id, dtlsParameters);
|
const connectTransport = await room.connectPeerTransport(socket.id, transport_id, dtlsParameters);
|
||||||
callback('success');
|
callback(connectTransport);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
log.error('Connect transport error', err.message);
|
log.error('Connect transport error', err.message);
|
||||||
callback({
|
callback({
|
||||||
@@ -1052,7 +1052,7 @@ function startServer() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on('produce', async ({ producerTransportId, kind, appData, rtpParameters }, callback) => {
|
socket.on('produce', async ({ producerTransportId, kind, appData, rtpParameters }, callback, errback) => {
|
||||||
if (!roomList.has(socket.room_id)) {
|
if (!roomList.has(socket.room_id)) {
|
||||||
return callback({ error: 'Room not found' });
|
return callback({ error: 'Room not found' });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "mirotalksfu",
|
"name": "mirotalksfu",
|
||||||
"version": "1.3.92",
|
"version": "1.3.93",
|
||||||
"description": "WebRTC SFU browser-based video calls",
|
"description": "WebRTC SFU browser-based video calls",
|
||||||
"main": "Server.js",
|
"main": "Server.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -38,8 +38,8 @@
|
|||||||
"author": "Miroslav Pejic",
|
"author": "Miroslav Pejic",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sentry/integrations": "7.106.0",
|
"@sentry/integrations": "7.106.1",
|
||||||
"@sentry/node": "7.106.0",
|
"@sentry/node": "7.106.1",
|
||||||
"axios": "^1.6.7",
|
"axios": "^1.6.7",
|
||||||
"body-parser": "1.20.2",
|
"body-parser": "1.20.2",
|
||||||
"colors": "1.4.0",
|
"colors": "1.4.0",
|
||||||
|
|||||||
@@ -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.3.92
|
* @version 1.3.93
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -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.3.92
|
* @version 1.3.93
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -387,8 +387,8 @@ class RoomClient {
|
|||||||
}
|
}
|
||||||
await this.joinAllowed(room);
|
await this.joinAllowed(room);
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((error) => {
|
||||||
console.log('Join error:', err);
|
console.error('Join error:', error);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -533,129 +533,121 @@ class RoomClient {
|
|||||||
// ####################################################
|
// ####################################################
|
||||||
|
|
||||||
async initTransports(device) {
|
async initTransports(device) {
|
||||||
try {
|
// ####################################################
|
||||||
// ####################################################
|
// PRODUCER TRANSPORT
|
||||||
// PRODUCER TRANSPORT
|
// ####################################################
|
||||||
// ####################################################
|
|
||||||
|
|
||||||
const producerTransportData = await this.socket.request('createWebRtcTransport', {
|
const producerTransportData = await this.socket.request('createWebRtcTransport', {
|
||||||
forceTcp: false,
|
forceTcp: false,
|
||||||
rtpCapabilities: device.rtpCapabilities,
|
rtpCapabilities: device.rtpCapabilities,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (producerTransportData.error) {
|
this.producerTransport = device.createSendTransport(producerTransportData);
|
||||||
throw new Error('Error creating WebRTC producer transport: ' + producerTransportData.error);
|
|
||||||
|
this.producerTransport.on('connect', async ({ dtlsParameters }, callback, errback) => {
|
||||||
|
try {
|
||||||
|
await this.socket.request('connectTransport', {
|
||||||
|
dtlsParameters,
|
||||||
|
transport_id: producerTransportData.id,
|
||||||
|
});
|
||||||
|
callback();
|
||||||
|
} catch (err) {
|
||||||
|
errback(err);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
this.producerTransport = device.createSendTransport(producerTransportData);
|
this.producerTransport.on('produce', async ({ kind, appData, rtpParameters }, callback, errback) => {
|
||||||
|
console.log('Going to produce', { kind, appData, rtpParameters });
|
||||||
this.producerTransport.on('connect', async ({ dtlsParameters }, callback, errback) => {
|
try {
|
||||||
try {
|
const { producer_id } = await this.socket.request('produce', {
|
||||||
await this.socket.request('connectTransport', {
|
producerTransportId: this.producerTransport.id,
|
||||||
dtlsParameters,
|
kind,
|
||||||
transport_id: producerTransportData.id,
|
appData,
|
||||||
});
|
rtpParameters,
|
||||||
callback();
|
});
|
||||||
} catch (err) {
|
if (producer_id.error) {
|
||||||
errback(err);
|
errback(producer_id.error);
|
||||||
}
|
} else {
|
||||||
});
|
|
||||||
|
|
||||||
this.producerTransport.on('produce', async ({ kind, appData, rtpParameters }, callback, errback) => {
|
|
||||||
console.log('Going to produce', { kind, appData, rtpParameters });
|
|
||||||
try {
|
|
||||||
const { producer_id } = await this.socket.request('produce', {
|
|
||||||
producerTransportId: this.producerTransport.id,
|
|
||||||
kind,
|
|
||||||
appData,
|
|
||||||
rtpParameters,
|
|
||||||
});
|
|
||||||
callback({ id: producer_id });
|
callback({ id: producer_id });
|
||||||
} catch (err) {
|
|
||||||
errback(err);
|
|
||||||
}
|
}
|
||||||
});
|
} catch (err) {
|
||||||
|
errback(err);
|
||||||
this.producerTransport.on('connectionstatechange', (state) => {
|
|
||||||
switch (state) {
|
|
||||||
case 'connecting':
|
|
||||||
console.log('Producer Transport connecting...');
|
|
||||||
break;
|
|
||||||
case 'connected':
|
|
||||||
console.log('Producer Transport connected');
|
|
||||||
break;
|
|
||||||
case 'failed':
|
|
||||||
console.warn('Producer Transport failed');
|
|
||||||
this.producerTransport.close();
|
|
||||||
// this.exit(true);
|
|
||||||
// this.refreshBrowser();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.producerTransport.on('icegatheringstatechange', (state) => {
|
|
||||||
console.log('Producer icegatheringstatechange', state);
|
|
||||||
});
|
|
||||||
|
|
||||||
// ####################################################
|
|
||||||
// CONSUMER TRANSPORT
|
|
||||||
// ####################################################
|
|
||||||
|
|
||||||
const consumerTransportData = await this.socket.request('createWebRtcTransport', {
|
|
||||||
forceTcp: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (consumerTransportData.error) {
|
|
||||||
throw new Error('Error creating WebRTC consumer transport: ' + consumerTransportData.error);
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
this.consumerTransport = device.createRecvTransport(consumerTransportData);
|
this.producerTransport.on('connectionstatechange', (state) => {
|
||||||
|
switch (state) {
|
||||||
|
case 'connecting':
|
||||||
|
console.log('Producer Transport connecting...');
|
||||||
|
break;
|
||||||
|
case 'connected':
|
||||||
|
console.log('Producer Transport connected');
|
||||||
|
break;
|
||||||
|
case 'failed':
|
||||||
|
console.warn('Producer Transport failed');
|
||||||
|
this.producerTransport.close();
|
||||||
|
// this.exit(true);
|
||||||
|
// this.refreshBrowser();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
this.consumerTransport.on('connect', async ({ dtlsParameters }, callback, errback) => {
|
this.producerTransport.on('icegatheringstatechange', (state) => {
|
||||||
try {
|
console.log('Producer icegatheringstatechange', state);
|
||||||
await this.socket.request('connectTransport', {
|
});
|
||||||
transport_id: this.consumerTransport.id,
|
|
||||||
dtlsParameters,
|
|
||||||
});
|
|
||||||
callback();
|
|
||||||
} catch (err) {
|
|
||||||
errback(err);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.consumerTransport.on('connectionstatechange', (state) => {
|
// ####################################################
|
||||||
switch (state) {
|
// CONSUMER TRANSPORT
|
||||||
case 'connecting':
|
// ####################################################
|
||||||
console.log('Consumer Transport connecting...');
|
|
||||||
break;
|
|
||||||
case 'connected':
|
|
||||||
console.log('Consumer Transport connected');
|
|
||||||
break;
|
|
||||||
case 'failed':
|
|
||||||
console.warn('Consumer Transport failed');
|
|
||||||
this.consumerTransport.close();
|
|
||||||
// this.exit(true);
|
|
||||||
// this.refreshBrowser();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.consumerTransport.on('icegatheringstatechange', (state) => {
|
const consumerTransportData = await this.socket.request('createWebRtcTransport', {
|
||||||
console.log('Consumer icegatheringstatechange', state);
|
forceTcp: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
// ####################################################
|
this.consumerTransport = device.createRecvTransport(consumerTransportData);
|
||||||
// TODO DATACHANNEL TRANSPORT
|
|
||||||
// ####################################################
|
|
||||||
|
|
||||||
//
|
this.consumerTransport.on('connect', async ({ dtlsParameters }, callback, errback) => {
|
||||||
} catch (error) {
|
try {
|
||||||
console.error('Error initializing transports', error);
|
await this.socket.request('connectTransport', {
|
||||||
}
|
transport_id: this.consumerTransport.id,
|
||||||
|
dtlsParameters,
|
||||||
|
});
|
||||||
|
callback();
|
||||||
|
} catch (err) {
|
||||||
|
errback(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.consumerTransport.on('connectionstatechange', (state) => {
|
||||||
|
switch (state) {
|
||||||
|
case 'connecting':
|
||||||
|
console.log('Consumer Transport connecting...');
|
||||||
|
break;
|
||||||
|
case 'connected':
|
||||||
|
console.log('Consumer Transport connected');
|
||||||
|
break;
|
||||||
|
case 'failed':
|
||||||
|
console.warn('Consumer Transport failed');
|
||||||
|
this.consumerTransport.close();
|
||||||
|
// this.exit(true);
|
||||||
|
// this.refreshBrowser();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.consumerTransport.on('icegatheringstatechange', (state) => {
|
||||||
|
console.log('Consumer icegatheringstatechange', state);
|
||||||
|
});
|
||||||
|
|
||||||
|
// ####################################################
|
||||||
|
// TODO DATACHANNEL TRANSPORT
|
||||||
|
// ####################################################
|
||||||
|
|
||||||
|
//
|
||||||
}
|
}
|
||||||
|
|
||||||
// ####################################################
|
// ####################################################
|
||||||
@@ -1895,44 +1887,35 @@ class RoomClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getConsumeStream(producerId, peer_id, type) {
|
async getConsumeStream(producerId, peer_id, type) {
|
||||||
try {
|
const { rtpCapabilities } = this.device;
|
||||||
const { rtpCapabilities } = this.device;
|
const data = await this.socket.request('consume', {
|
||||||
const data = await this.socket.request('consume', {
|
rtpCapabilities,
|
||||||
rtpCapabilities,
|
consumerTransportId: this.consumerTransport.id,
|
||||||
consumerTransportId: this.consumerTransport.id,
|
producerId,
|
||||||
producerId,
|
});
|
||||||
});
|
|
||||||
|
|
||||||
console.log('DATA', data);
|
console.log('DATA', data);
|
||||||
|
|
||||||
if (!data || !data.id || !data.kind || !data.rtpParameters) {
|
const { id, kind, rtpParameters } = data;
|
||||||
throw new Error('Invalid data received from server');
|
const codecOptions = {};
|
||||||
}
|
const streamId = peer_id + (type == mediaType.screen ? '-screen-sharing' : '-mic-webcam');
|
||||||
|
const consumer = await this.consumerTransport.consume({
|
||||||
|
id,
|
||||||
|
producerId,
|
||||||
|
kind,
|
||||||
|
rtpParameters,
|
||||||
|
codecOptions,
|
||||||
|
streamId,
|
||||||
|
});
|
||||||
|
|
||||||
const { id, kind, rtpParameters } = data;
|
const stream = new MediaStream();
|
||||||
const codecOptions = {};
|
stream.addTrack(consumer.track);
|
||||||
const streamId = peer_id + (type == mediaType.screen ? '-screen-sharing' : '-mic-webcam');
|
|
||||||
const consumer = await this.consumerTransport.consume({
|
|
||||||
id,
|
|
||||||
producerId,
|
|
||||||
kind,
|
|
||||||
rtpParameters,
|
|
||||||
codecOptions,
|
|
||||||
streamId,
|
|
||||||
});
|
|
||||||
|
|
||||||
const stream = new MediaStream();
|
return {
|
||||||
stream.addTrack(consumer.track);
|
consumer,
|
||||||
|
stream,
|
||||||
return {
|
kind,
|
||||||
consumer,
|
};
|
||||||
stream,
|
|
||||||
kind,
|
|
||||||
};
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error in getConsumeStream', error);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handleConsumer(id, type, stream, peer_name, peer_info) {
|
handleConsumer(id, type, stream, peer_name, peer_info) {
|
||||||
|
|||||||
المرجع في مشكلة جديدة
حظر مستخدم