[mirotalksfu] - refactoring
هذا الالتزام موجود في:
111
app/src/Peer.js
111
app/src/Peer.js
@@ -92,6 +92,10 @@ module.exports = class Peer {
|
|||||||
// TRANSPORT
|
// TRANSPORT
|
||||||
// ####################################################
|
// ####################################################
|
||||||
|
|
||||||
|
hasTransport(transport_id) {
|
||||||
|
return this.transports.has(transport_id);
|
||||||
|
}
|
||||||
|
|
||||||
getTransports() {
|
getTransports() {
|
||||||
return JSON.parse(JSON.stringify([...this.transports]));
|
return JSON.parse(JSON.stringify([...this.transports]));
|
||||||
}
|
}
|
||||||
@@ -109,16 +113,28 @@ module.exports = class Peer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async connectTransport(transport_id, dtlsParameters) {
|
async connectTransport(transport_id, dtlsParameters) {
|
||||||
|
if (!transport_id || !dtlsParameters) {
|
||||||
|
throw new Error('Missing required parameters for connecting a transport');
|
||||||
|
}
|
||||||
|
|
||||||
if (!this.transports.has(transport_id)) {
|
if (!this.transports.has(transport_id)) {
|
||||||
throw new Error(`Transport with ID ${transport_id} not found`);
|
throw new Error(`Transport with ID ${transport_id} not found`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const transport = this.transports.get(transport_id);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await this.transports.get(transport_id).connect({
|
// Connect the transport
|
||||||
dtlsParameters: dtlsParameters,
|
await transport.connect({ dtlsParameters });
|
||||||
|
log.debug('Transport connected successfully', {
|
||||||
|
transport_id,
|
||||||
|
peer_name: this.peer_name,
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
log.error(`Failed to connect transport with ID ${transport_id}`, error);
|
log.error(`Failed to connect transport with ID ${transport_id}`, {
|
||||||
|
error: error.message,
|
||||||
|
peer_name: this.peer_name,
|
||||||
|
});
|
||||||
throw new Error(`Failed to connect transport with ID ${transport_id}`);
|
throw new Error(`Failed to connect transport with ID ${transport_id}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -173,6 +189,10 @@ module.exports = class Peer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async createProducer(producerTransportId, producer_rtpParameters, producer_kind, producer_type) {
|
async createProducer(producerTransportId, producer_rtpParameters, producer_kind, producer_type) {
|
||||||
|
if (!producerTransportId || !producer_rtpParameters || !producer_kind || !producer_type) {
|
||||||
|
throw new Error('Missing required parameters for creating a producer');
|
||||||
|
}
|
||||||
|
|
||||||
if (!this.transports.has(producerTransportId)) {
|
if (!this.transports.has(producerTransportId)) {
|
||||||
throw new Error(`Producer transport with ID ${producerTransportId} not found`);
|
throw new Error(`Producer transport with ID ${producerTransportId} not found`);
|
||||||
}
|
}
|
||||||
@@ -186,10 +206,18 @@ module.exports = class Peer {
|
|||||||
rtpParameters: producer_rtpParameters,
|
rtpParameters: producer_rtpParameters,
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
log.error(`Error creating producer for transport ID ${producerTransportId}:`, error);
|
log.error(`Error creating producer for transport ID ${producerTransportId}`, {
|
||||||
|
error: error.message,
|
||||||
|
producer_kind,
|
||||||
|
producer_type,
|
||||||
|
});
|
||||||
throw new Error(`Failed to create producer for transport ID ${producerTransportId}`);
|
throw new Error(`Failed to create producer for transport ID ${producerTransportId}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!producer) {
|
||||||
|
throw new Error(`Producer creation failed for transport ID ${producerTransportId}`);
|
||||||
|
}
|
||||||
|
|
||||||
const { id, appData, type, kind, rtpParameters } = producer;
|
const { id, appData, type, kind, rtpParameters } = producer;
|
||||||
|
|
||||||
appData.mediaType = producer_type;
|
appData.mediaType = producer_type;
|
||||||
@@ -207,7 +235,7 @@ module.exports = class Peer {
|
|||||||
temporalLayer,
|
temporalLayer,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
log.debug('Producer ----->', { type, kind });
|
log.debug('Producer created ----->', { type, kind });
|
||||||
}
|
}
|
||||||
|
|
||||||
producer.on('transportclose', () => {
|
producer.on('transportclose', () => {
|
||||||
@@ -222,23 +250,29 @@ module.exports = class Peer {
|
|||||||
if (!this.producers.has(producer_id)) return;
|
if (!this.producers.has(producer_id)) return;
|
||||||
|
|
||||||
const producer = this.getProducer(producer_id);
|
const producer = this.getProducer(producer_id);
|
||||||
const { id, kind, type, appData } = producer;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
producer.close();
|
producer.close();
|
||||||
|
|
||||||
|
log.debug('Producer closed successfully', {
|
||||||
|
producer_id: producer.id,
|
||||||
|
peer_name: this.peer_name,
|
||||||
|
kind: producer.kind,
|
||||||
|
type: producer.type,
|
||||||
|
appData: producer.appData,
|
||||||
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
log.warn('Close Producer', error.message);
|
log.error(`Error closing producer with ID ${producer_id}`, {
|
||||||
|
error: error.message,
|
||||||
|
peer_name: this.peer_name,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
this.delProducer(producer_id);
|
this.delProducer(producer_id);
|
||||||
|
|
||||||
log.debug('Producer closed and deleted', {
|
log.debug('Producer removed from peer', {
|
||||||
|
producer_id: producer.id,
|
||||||
peer_name: this.peer_name,
|
peer_name: this.peer_name,
|
||||||
kind: kind,
|
|
||||||
type: type,
|
|
||||||
appData: appData,
|
|
||||||
producer_id: id,
|
|
||||||
producer_closed: producer.closed,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -263,6 +297,10 @@ module.exports = class Peer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async createConsumer(consumer_transport_id, producerId, rtpCapabilities) {
|
async createConsumer(consumer_transport_id, producerId, rtpCapabilities) {
|
||||||
|
if (!consumer_transport_id || !producerId || !rtpCapabilities) {
|
||||||
|
throw new Error('Missing required parameters for creating a consumer');
|
||||||
|
}
|
||||||
|
|
||||||
if (!this.transports.has(consumer_transport_id)) {
|
if (!this.transports.has(consumer_transport_id)) {
|
||||||
throw new Error(`Consumer transport with ID ${consumer_transport_id} not found`);
|
throw new Error(`Consumer transport with ID ${consumer_transport_id} not found`);
|
||||||
}
|
}
|
||||||
@@ -275,14 +313,21 @@ module.exports = class Peer {
|
|||||||
producerId,
|
producerId,
|
||||||
rtpCapabilities,
|
rtpCapabilities,
|
||||||
enableRtx: true, // Enable NACK for OPUS.
|
enableRtx: true, // Enable NACK for OPUS.
|
||||||
paused: true,
|
paused: true, // Start the consumer in a paused state
|
||||||
ignoreDtx: true,
|
ignoreDtx: true, // Ignore DTX (Discontinuous Transmission)
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
log.error(`Error creating consumer for transport ID ${consumer_transport_id}`, error);
|
log.error(`Error creating consumer for transport ID ${consumer_transport_id}`, {
|
||||||
|
error: error.message,
|
||||||
|
producerId,
|
||||||
|
});
|
||||||
throw new Error(`Failed to create consumer for transport ID ${consumer_transport_id}`);
|
throw new Error(`Failed to create consumer for transport ID ${consumer_transport_id}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!consumer) {
|
||||||
|
throw new Error(`Consumer creation failed for transport ID ${consumer_transport_id}`);
|
||||||
|
}
|
||||||
|
|
||||||
const { id, type, kind, rtpParameters, producerPaused } = consumer;
|
const { id, type, kind, rtpParameters, producerPaused } = consumer;
|
||||||
|
|
||||||
this.addConsumer(id, consumer);
|
this.addConsumer(id, consumer);
|
||||||
@@ -310,7 +355,7 @@ module.exports = class Peer {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log.debug('Consumer ----->', { type, kind });
|
log.debug('Consumer created ----->', { type, kind });
|
||||||
}
|
}
|
||||||
|
|
||||||
consumer.on('transportclose', () => {
|
consumer.on('transportclose', () => {
|
||||||
@@ -319,14 +364,14 @@ module.exports = class Peer {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
consumer: consumer,
|
consumer,
|
||||||
params: {
|
params: {
|
||||||
producerId,
|
producerId,
|
||||||
id: id,
|
id,
|
||||||
kind: kind,
|
kind,
|
||||||
rtpParameters: rtpParameters,
|
rtpParameters,
|
||||||
type: type,
|
type,
|
||||||
producerPaused: producerPaused,
|
producerPaused,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -335,22 +380,28 @@ module.exports = class Peer {
|
|||||||
if (!this.consumers.has(consumer_id)) return;
|
if (!this.consumers.has(consumer_id)) return;
|
||||||
|
|
||||||
const consumer = this.getConsumer(consumer_id);
|
const consumer = this.getConsumer(consumer_id);
|
||||||
const { id, kind, type } = consumer;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
consumer.close();
|
consumer.close();
|
||||||
|
|
||||||
|
log.debug('Consumer closed successfully', {
|
||||||
|
consumer_id: consumer.id,
|
||||||
|
peer_name: this.peer_name,
|
||||||
|
kind: consumer.kind,
|
||||||
|
type: consumer.type,
|
||||||
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
log.warn('Close Consumer', error.message);
|
log.error(`Error closing consumer with ID ${consumer_id}`, {
|
||||||
|
error: error.message,
|
||||||
|
peer_name: this.peer_name,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
this.delConsumer(consumer_id);
|
this.delConsumer(consumer_id);
|
||||||
|
|
||||||
log.debug('Consumer closed and deleted', {
|
log.debug('Consumer removed from peer', {
|
||||||
|
consumer_id: consumer.id,
|
||||||
peer_name: this.peer_name,
|
peer_name: this.peer_name,
|
||||||
kind: kind,
|
|
||||||
type: type,
|
|
||||||
consumer_id: id,
|
|
||||||
consumer_closed: consumer.closed,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
159
app/src/Room.js
159
app/src/Room.js
@@ -328,11 +328,10 @@ module.exports = class Room {
|
|||||||
}
|
}
|
||||||
|
|
||||||
closeRouter() {
|
closeRouter() {
|
||||||
|
this.stopAudioLevelObserver();
|
||||||
|
this.stopActiveSpeakerObserver();
|
||||||
this.router.close();
|
this.router.close();
|
||||||
log.debug('Close Room router', {
|
log.debug('Router closed', { router_id: this.router.id });
|
||||||
router_id: this.router.id,
|
|
||||||
router_closed: this.router.closed,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ####################################################
|
// ####################################################
|
||||||
@@ -397,6 +396,14 @@ module.exports = class Room {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stopAudioLevelObserver() {
|
||||||
|
if (this.audioLevelObserver) {
|
||||||
|
this.audioLevelObserver.close();
|
||||||
|
this.audioLevelObserver = null;
|
||||||
|
log.debug('Audio Level Observer closed');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ####################################################
|
// ####################################################
|
||||||
// PRODUCER DOMINANT ACTIVE SPEAKER
|
// PRODUCER DOMINANT ACTIVE SPEAKER
|
||||||
// ####################################################
|
// ####################################################
|
||||||
@@ -431,6 +438,14 @@ module.exports = class Room {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stopActiveSpeakerObserver() {
|
||||||
|
if (this.activeSpeakerObserver) {
|
||||||
|
this.activeSpeakerObserver.close();
|
||||||
|
this.activeSpeakerObserver = null;
|
||||||
|
log.debug('Active Speaker Observer closed');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ####################################################
|
// ####################################################
|
||||||
// ROOM MODERATOR
|
// ROOM MODERATOR
|
||||||
// ####################################################
|
// ####################################################
|
||||||
@@ -537,31 +552,44 @@ module.exports = class Room {
|
|||||||
// WebRTC TRANSPORT
|
// WebRTC TRANSPORT
|
||||||
// ####################################################
|
// ####################################################
|
||||||
|
|
||||||
|
getWebRtcTransportOptions() {
|
||||||
|
const { iceConsentTimeout = 35, initialAvailableOutgoingBitrate, listenInfos } = this.webRtcTransport;
|
||||||
|
return {
|
||||||
|
...(this.webRtcServerActive ? { webRtcServer: this.webRtcServer } : { listenInfos: listenInfos }),
|
||||||
|
enableUdp: true,
|
||||||
|
enableTcp: true,
|
||||||
|
preferUdp: true,
|
||||||
|
iceConsentTimeout,
|
||||||
|
initialAvailableOutgoingBitrate,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
async createWebRtcTransport(socket_id) {
|
async createWebRtcTransport(socket_id) {
|
||||||
if (!this.peers.has(socket_id)) {
|
if (!this.peers.has(socket_id)) {
|
||||||
throw new Error(`Peer with socket ID ${socket_id} not found in the room`);
|
throw new Error(`Peer with socket ID ${socket_id} not found in the room`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const { maxIncomingBitrate, initialAvailableOutgoingBitrate, listenInfos } = this.webRtcTransport;
|
const webRtcTransportOptions = this.getWebRtcTransportOptions();
|
||||||
|
|
||||||
const webRtcTransportOptions = {
|
|
||||||
...(this.webRtcServerActive ? { webRtcServer: this.webRtcServer } : { listenInfos: listenInfos }),
|
|
||||||
enableUdp: true,
|
|
||||||
enableTcp: true,
|
|
||||||
preferUdp: true,
|
|
||||||
iceConsentTimeout: 35,
|
|
||||||
initialAvailableOutgoingBitrate,
|
|
||||||
};
|
|
||||||
|
|
||||||
log.debug('webRtcTransportOptions ----->', webRtcTransportOptions);
|
log.debug('webRtcTransportOptions ----->', webRtcTransportOptions);
|
||||||
|
|
||||||
const transport = await this.router.createWebRtcTransport(webRtcTransportOptions);
|
let transport;
|
||||||
|
try {
|
||||||
|
transport = await this.router.createWebRtcTransport(webRtcTransportOptions);
|
||||||
|
if (!transport) {
|
||||||
|
throw new Error('Failed to create WebRTC Transport');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
log.error('Error creating WebRTC Transport', { error: error.message, socket_id });
|
||||||
|
throw new Error('Error creating WebRTC Transport');
|
||||||
|
}
|
||||||
|
|
||||||
if (!transport) {
|
if (transport.closed) {
|
||||||
throw new Error('Failed to create WebRtc Transport');
|
throw new Error('Transport is already closed');
|
||||||
}
|
}
|
||||||
|
|
||||||
const { id, type, iceParameters, iceCandidates, dtlsParameters } = transport;
|
const { id, type, iceParameters, iceCandidates, dtlsParameters } = transport;
|
||||||
|
const { maxIncomingBitrate } = this.webRtcTransport;
|
||||||
|
|
||||||
if (maxIncomingBitrate) {
|
if (maxIncomingBitrate) {
|
||||||
try {
|
try {
|
||||||
@@ -580,7 +608,12 @@ module.exports = class Room {
|
|||||||
throw new Error(`Failed to add peer transport ${id}`);
|
throw new Error(`Failed to add peer transport ${id}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
log.debug('Transport created', { transportId: id, transportType: type });
|
log.debug('Transport created', {
|
||||||
|
room_id: this.id,
|
||||||
|
transport_id: transport.id,
|
||||||
|
type: type,
|
||||||
|
peer_name: peer.peer_name,
|
||||||
|
});
|
||||||
|
|
||||||
const { peer_name } = peer;
|
const { peer_name } = peer;
|
||||||
|
|
||||||
@@ -597,12 +630,22 @@ module.exports = class Room {
|
|||||||
});
|
});
|
||||||
|
|
||||||
transport.on('icestatechange', (iceState) => {
|
transport.on('icestatechange', (iceState) => {
|
||||||
if (iceState === 'disconnected' || iceState === 'closed') {
|
log.warn('ICE state changed', {
|
||||||
log.warn('ICE state changed, closing peer', {
|
peer_name: peer_name,
|
||||||
peer_name: peer_name,
|
transport_id: id,
|
||||||
transport_id: id,
|
iceState: iceState,
|
||||||
iceState: iceState,
|
});
|
||||||
});
|
|
||||||
|
if (iceState === 'disconnected') {
|
||||||
|
log.warn(`ICE state disconnected for transport ${transport.id}, waiting before closing`);
|
||||||
|
setTimeout(() => {
|
||||||
|
if (transport.iceState === 'disconnected') {
|
||||||
|
log.warn(`Closing transport ${transport.id} due to prolonged ICE disconnection`);
|
||||||
|
transport.close();
|
||||||
|
}
|
||||||
|
}, 5000); // Wait 5 seconds before closing
|
||||||
|
} else if (iceState === 'closed') {
|
||||||
|
log.warn(`ICE state closed for transport ${transport.id}`);
|
||||||
transport.close();
|
transport.close();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -642,6 +685,10 @@ module.exports = class Room {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async connectPeerTransport(socket_id, transport_id, dtlsParameters) {
|
async connectPeerTransport(socket_id, transport_id, dtlsParameters) {
|
||||||
|
if (!socket_id || !transport_id || !dtlsParameters) {
|
||||||
|
throw new Error('Missing required parameters for connecting peer transport');
|
||||||
|
}
|
||||||
|
|
||||||
if (!this.peers.has(socket_id)) {
|
if (!this.peers.has(socket_id)) {
|
||||||
throw new Error(`Peer with socket ID ${socket_id} not found in the room`);
|
throw new Error(`Peer with socket ID ${socket_id} not found in the room`);
|
||||||
}
|
}
|
||||||
@@ -650,8 +697,17 @@ module.exports = class Room {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
await peer.connectTransport(transport_id, dtlsParameters);
|
await peer.connectTransport(transport_id, dtlsParameters);
|
||||||
|
log.debug('Peer transport connected successfully', {
|
||||||
|
socket_id,
|
||||||
|
transport_id,
|
||||||
|
peer_name: peer.peer_name,
|
||||||
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
log.error(`Failed to connect peer transport for socket ID ${socket_id}`, error);
|
log.error(`Failed to connect peer transport for socket ID ${socket_id}`, {
|
||||||
|
transport_id,
|
||||||
|
error: error.message,
|
||||||
|
peer_name: peer.peer_name,
|
||||||
|
});
|
||||||
throw new Error(`Failed to connect transport for peer with socket ID ${socket_id}`);
|
throw new Error(`Failed to connect transport for peer with socket ID ${socket_id}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -663,22 +719,33 @@ module.exports = class Room {
|
|||||||
// ####################################################
|
// ####################################################
|
||||||
|
|
||||||
async produce(socket_id, producerTransportId, rtpParameters, kind, type) {
|
async produce(socket_id, producerTransportId, rtpParameters, kind, type) {
|
||||||
|
if (!socket_id || !producerTransportId || !rtpParameters || !kind || !type) {
|
||||||
|
throw new Error('Missing required parameters for producing media');
|
||||||
|
}
|
||||||
|
|
||||||
if (!this.peers.has(socket_id)) {
|
if (!this.peers.has(socket_id)) {
|
||||||
throw new Error(`Peer with socket ID ${socket_id} not found in the room`);
|
throw new Error(`Peer with socket ID ${socket_id} not found in the room`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const peer = this.getPeer(socket_id);
|
const peer = this.getPeer(socket_id);
|
||||||
|
|
||||||
const { peer_name, peer_info } = peer;
|
const { peer_name, peer_info } = peer;
|
||||||
|
|
||||||
let peerProducer;
|
if (!peer.hasTransport(producerTransportId)) {
|
||||||
|
throw new Error(`Transport with ID ${producerTransportId} not found for peer ${socket_id}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
let peerProducer;
|
||||||
try {
|
try {
|
||||||
peerProducer = await peer.createProducer(producerTransportId, rtpParameters, kind, type);
|
peerProducer = await peer.createProducer(producerTransportId, rtpParameters, kind, type);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
log.error(`Error creating producer for peer ${peer_name} with socket ID ${socket_id}`, error);
|
log.error(`Error creating producer for peer ${peer.peer_name} with socket ID ${socket_id}`, {
|
||||||
|
producerTransportId,
|
||||||
|
kind,
|
||||||
|
type,
|
||||||
|
error: error.message,
|
||||||
|
});
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Error creating producer for peer ${peer_name} with transport ID ${producerTransportId} type ${type} for peer ${socket_id}`,
|
`Failed to create producer for peer ${peer.peer_name} with transport ID ${producerTransportId}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -700,6 +767,13 @@ module.exports = class Room {
|
|||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
log.debug('Producer created successfully', {
|
||||||
|
producer_id: id,
|
||||||
|
peer_name: peer.peer_name,
|
||||||
|
kind,
|
||||||
|
type,
|
||||||
|
});
|
||||||
|
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -721,12 +795,15 @@ module.exports = class Room {
|
|||||||
// ####################################################
|
// ####################################################
|
||||||
|
|
||||||
async consume(socket_id, consumer_transport_id, producerId, rtpCapabilities, type) {
|
async consume(socket_id, consumer_transport_id, producerId, rtpCapabilities, type) {
|
||||||
|
if (!socket_id || !consumer_transport_id || !producerId || !rtpCapabilities || !type) {
|
||||||
|
throw new Error('Missing required parameters for consuming media');
|
||||||
|
}
|
||||||
|
|
||||||
if (!this.peers.has(socket_id)) {
|
if (!this.peers.has(socket_id)) {
|
||||||
throw new Error(`Peer with socket ID ${socket_id} not found in the room`);
|
throw new Error(`Peer with socket ID ${socket_id} not found in the room`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const peer = this.getPeer(socket_id);
|
const peer = this.getPeer(socket_id);
|
||||||
|
|
||||||
const { peer_name } = peer;
|
const { peer_name } = peer;
|
||||||
|
|
||||||
if (!this.router.canConsume({ producerId, rtpCapabilities })) {
|
if (!this.router.canConsume({ producerId, rtpCapabilities })) {
|
||||||
@@ -739,7 +816,12 @@ module.exports = class Room {
|
|||||||
try {
|
try {
|
||||||
peerConsumer = await peer.createConsumer(consumer_transport_id, producerId, rtpCapabilities);
|
peerConsumer = await peer.createConsumer(consumer_transport_id, producerId, rtpCapabilities);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
log.error(`Error creating consumer for peer with socket ID ${socket_id}`, error);
|
log.error(`Error creating consumer for peer ${peer_name} with socket ID ${socket_id}`, {
|
||||||
|
consumer_transport_id,
|
||||||
|
producerId,
|
||||||
|
type,
|
||||||
|
error: error.message,
|
||||||
|
});
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Failed to create consumer for peer ${peer_name} with transport ID ${consumer_transport_id} and producer ID ${producerId} type ${type} for peer ${socket_id}`,
|
`Failed to create consumer for peer ${peer_name} with transport ID ${consumer_transport_id} and producer ID ${producerId} type ${type} for peer ${socket_id}`,
|
||||||
);
|
);
|
||||||
@@ -752,11 +834,14 @@ module.exports = class Room {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const { consumer, params } = peerConsumer;
|
const { consumer, params } = peerConsumer;
|
||||||
|
|
||||||
const { id, kind } = consumer;
|
const { id, kind } = consumer;
|
||||||
|
|
||||||
consumer.on('producerclose', () => {
|
consumer.on('producerclose', () => {
|
||||||
log.debug('Consumer closed due to "producerclose" event');
|
log.debug('Consumer closed due to "producerclose" event', {
|
||||||
|
consumer_id: id,
|
||||||
|
producer_id: producerId,
|
||||||
|
peer_name,
|
||||||
|
});
|
||||||
|
|
||||||
peer.removeConsumer(id);
|
peer.removeConsumer(id);
|
||||||
|
|
||||||
@@ -767,6 +852,14 @@ module.exports = class Room {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
log.debug('Consumer created successfully', {
|
||||||
|
consumer_id: id,
|
||||||
|
producer_id: producerId,
|
||||||
|
peer_name,
|
||||||
|
kind,
|
||||||
|
type,
|
||||||
|
});
|
||||||
|
|
||||||
return params;
|
return params;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -64,7 +64,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.8.35
|
* @version 1.8.36
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -1448,6 +1448,8 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
||||||
|
iceConsentTimeout: 35, // Timeout for ICE consent (seconds)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bandwidth Control Settings
|
* Bandwidth Control Settings
|
||||||
* Kubernetes implications:
|
* Kubernetes implications:
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "mirotalksfu",
|
"name": "mirotalksfu",
|
||||||
"version": "1.8.35",
|
"version": "1.8.36",
|
||||||
"description": "WebRTC SFU browser-based video calls",
|
"description": "WebRTC SFU browser-based video calls",
|
||||||
"main": "Server.js",
|
"main": "Server.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -84,7 +84,7 @@
|
|||||||
"mediasoup": "3.15.7",
|
"mediasoup": "3.15.7",
|
||||||
"mediasoup-client": "3.10.0",
|
"mediasoup-client": "3.10.0",
|
||||||
"nodemailer": "^6.10.1",
|
"nodemailer": "^6.10.1",
|
||||||
"openai": "^4.96.2",
|
"openai": "^4.97.0",
|
||||||
"qs": "6.14.0",
|
"qs": "6.14.0",
|
||||||
"sanitize-filename": "^1.6.3",
|
"sanitize-filename": "^1.6.3",
|
||||||
"socket.io": "4.8.1",
|
"socket.io": "4.8.1",
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ let BRAND = {
|
|||||||
},
|
},
|
||||||
about: {
|
about: {
|
||||||
imageUrl: '../images/mirotalk-logo.gif',
|
imageUrl: '../images/mirotalk-logo.gif',
|
||||||
title: '<strong>WebRTC SFU v1.8.35</strong>',
|
title: '<strong>WebRTC SFU v1.8.36</strong>',
|
||||||
html: `
|
html: `
|
||||||
<button
|
<button
|
||||||
id="support-button"
|
id="support-button"
|
||||||
|
|||||||
@@ -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.8.35
|
* @version 1.8.36
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -5351,7 +5351,7 @@ function showAbout() {
|
|||||||
position: 'center',
|
position: 'center',
|
||||||
imageUrl: BRAND.about?.imageUrl && BRAND.about.imageUrl.trim() !== '' ? BRAND.about.imageUrl : image.about,
|
imageUrl: BRAND.about?.imageUrl && BRAND.about.imageUrl.trim() !== '' ? BRAND.about.imageUrl : image.about,
|
||||||
customClass: { image: 'img-about' },
|
customClass: { image: 'img-about' },
|
||||||
title: BRAND.about?.title && BRAND.about.title.trim() !== '' ? BRAND.about.title : 'WebRTC SFU v1.8.35',
|
title: BRAND.about?.title && BRAND.about.title.trim() !== '' ? BRAND.about.title : 'WebRTC SFU v1.8.36',
|
||||||
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.8.35
|
* @version 1.8.36
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
المرجع في مشكلة جديدة
حظر مستخدم