[mirotalksfu] - improve nodemailer, update dep, speaker focus WIP

هذا الالتزام موجود في:
Miroslav Pejic
2025-06-08 15:14:08 +02:00
الأصل 561dfb474d
التزام 7869df811e
12 ملفات معدلة مع 190 إضافات و62 حذوفات

عرض الملف

@@ -205,6 +205,8 @@ module.exports = class Peer {
kind: producer_kind,
rtpParameters: producer_rtpParameters,
});
this.addProducer(producer.id, producer);
} catch (error) {
log.error(`Error creating producer for transport ID ${producerTransportId}`, {
error: error.message,
@@ -222,8 +224,6 @@ module.exports = class Peer {
appData.mediaType = producer_type;
this.addProducer(id, producer);
if (['simulcast', 'svc'].includes(type)) {
const { scalabilityMode } = rtpParameters.encodings[0];
const spatialLayer = parseInt(scalabilityMode.substring(1, 2)); // 1/2/3
@@ -316,6 +316,8 @@ module.exports = class Peer {
paused: true, // Start the consumer in a paused state
ignoreDtx: true, // Ignore DTX (Discontinuous Transmission)
});
this.addConsumer(consumer.id, consumer);
} catch (error) {
log.error(`Error creating consumer for transport ID ${consumer_transport_id}`, {
error: error.message,
@@ -330,8 +332,6 @@ module.exports = class Peer {
const { id, type, kind, rtpParameters, producerPaused } = consumer;
this.addConsumer(id, consumer);
if (['simulcast', 'svc'].includes(type)) {
// simulcast - L1T3/L2T3/L3T3 | svc - L3T3
const { scalabilityMode } = rtpParameters.encodings[0];

عرض الملف

@@ -102,6 +102,7 @@ module.exports = class Room {
videoAIEnabled: this.videoAIEnabled,
thereIsPolls: this.thereIsPolls(),
shareMediaData: this.shareMediaData,
dominantSpeaker: this.activeSpeakerObserverEnabled,
peers: JSON.stringify([...this.peers]),
};
}
@@ -311,10 +312,16 @@ module.exports = class Room {
.then((router) => {
this.router = router;
if (this.audioLevelObserverEnabled) {
this.startAudioLevelObservation();
log.info('Audio Level Observer enabled, starting observation...');
this.startAudioLevelObservation().catch((err) => {
log.error('Failed to start audio level observation', err);
});
}
if (this.activeSpeakerObserverEnabled) {
this.startActiveSpeakerObserver();
log.info('Active Speaker Observer enabled, starting observation...');
this.startActiveSpeakerObserver().catch((err) => {
log.error('Failed to start active speaker observer', err);
});
}
this.router.observer.on('close', () => {
log.info('---------------> Router is now closed as the last peer has left the room', {
@@ -385,9 +392,9 @@ module.exports = class Room {
peer_name: peer_name,
audioVolume: audioVolume,
};
// Uncomment the following line for debugging
// log.debug('Sending audio volume', data);
this.sendToAll('audioVolume', data);
return;
}
});
});
@@ -401,6 +408,7 @@ module.exports = class Room {
addProducerToAudioLevelObserver(producer) {
if (this.audioLevelObserverEnabled) {
this.audioLevelObserver.addProducer(producer);
log.info('Producer added to audio level observer', { producer });
}
}
@@ -417,25 +425,40 @@ module.exports = class Room {
// ####################################################
async startActiveSpeakerObserver() {
log.debug('Start activeSpeakerObserver for signaling dominant speaker...');
this.activeSpeakerObserver = await this.router.createActiveSpeakerObserver();
this.activeSpeakerObserver.on('dominantspeaker', (dominantSpeaker) => {
if (!dominantSpeaker.producer) {
return;
}
log.debug('activeSpeakerObserver "dominantspeaker" event', dominantSpeaker.producer.id);
this.peers.forEach((peer) => {
const { id, peer_audio, peer_name } = peer;
peer.producers.forEach((peerProducer) => {
if (
peerProducer.id === dominantSpeaker.producer.id &&
peerProducer.kind === 'audio' &&
peer_audio
) {
const data = {
peer_id: id,
peer_name: peer_name,
};
// log.debug('Sending dominant speaker', data);
this.sendToAll('dominantSpeaker', data);
if (peer.producers instanceof Map) {
for (const peerProducer of peer.producers.values()) {
if (
peerProducer.id === dominantSpeaker.producer.id &&
peerProducer.kind === 'audio' &&
peer_audio
) {
let videoProducerId = null;
for (const p of peer.producers.values()) {
if (p.kind === 'video') {
videoProducerId = p.id;
break;
}
}
const data = {
producer_id: videoProducerId,
peer_id: id,
peer_name: peer_name,
};
log.debug('Sending dominant speaker', data);
this.sendToAll('dominantSpeaker', data);
break;
}
}
});
}
});
});
}
@@ -443,6 +466,7 @@ module.exports = class Room {
addProducerToActiveSpeakerObserver(producer) {
if (this.activeSpeakerObserverEnabled) {
this.activeSpeakerObserver.addProducer(producer);
log.info('Producer added to active speaker observer', { producer });
}
}

عرض الملف

@@ -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 CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970
* @author Miroslav Pejic - miroslav.pejic.85@gmail.com
* @version 1.8.61
* @version 1.8.62
*
*/
@@ -1976,7 +1976,7 @@ function startServer() {
peerInfo: peerInfo,
});
// add & monitor producer audio level and active speaker
// add & monitor producer audio level and dominant speaker
if (kind === 'audio') {
room.addProducerToAudioLevelObserver({ producerId: producer_id });
room.addProducerToActiveSpeakerObserver({ producerId: producer_id });

عرض الملف

@@ -647,6 +647,7 @@ module.exports = {
* - port : SMTP port (default: 587 for TLS)
* - username : SMTP auth username
* - password : SMTP auth password (store ONLY in .env)
* - from : Sender email address (default: same as username)
* - sendTo : Recipient email for alerts
*
* Common Providers:
@@ -669,6 +670,7 @@ module.exports = {
port: parseInt(process.env.EMAIL_PORT) || 587,
username: process.env.EMAIL_USERNAME || 'your_username',
password: process.env.EMAIL_PASSWORD || 'your_password',
from: process.env.EMAIL_FROM || process.env.EMAIL_USERNAME,
sendTo: process.env.EMAIL_SEND_TO || 'sfu.mirotalk@gmail.com',
},
@@ -1341,10 +1343,10 @@ module.exports = {
*/
router: {
// Enable audio level monitoring (for detecting who is speaking)
audioLevelObserverEnabled: true,
audioLevelObserverEnabled: process.env.MEDIASOUP_ROUTER_AUDIO_LEVEL_OBSERVER_ENABLED !== 'false',
// Disable active speaker detection (uses more CPU)
activeSpeakerObserverEnabled: false,
activeSpeakerObserverEnabled: process.env.MEDIASOUP_ROUTER_ACTIVE_SPEAKER_OBSERVER_ENABLED === 'true',
/**
* Supported Media Codecs

عرض الملف

@@ -15,6 +15,7 @@ const EMAIL_HOST = emailConfig.host || false;
const EMAIL_PORT = emailConfig.port || false;
const EMAIL_USERNAME = emailConfig.username || false;
const EMAIL_PASSWORD = emailConfig.password || false;
const EMAIL_FROM = emailConfig.from || emailConfig.username;
const EMAIL_SEND_TO = emailConfig.sendTo || false;
if (EMAIL_ALERT && EMAIL_HOST && EMAIL_PORT && EMAIL_USERNAME && EMAIL_PASSWORD && EMAIL_SEND_TO) {
@@ -24,12 +25,16 @@ if (EMAIL_ALERT && EMAIL_HOST && EMAIL_PORT && EMAIL_USERNAME && EMAIL_PASSWORD
port: EMAIL_PORT,
username: EMAIL_USERNAME,
password: EMAIL_PASSWORD,
from: EMAIL_FROM,
to: EMAIL_SEND_TO,
});
}
const IS_TLS_PORT = EMAIL_PORT === 465;
const transport = nodemailer.createTransport({
host: EMAIL_HOST,
port: EMAIL_PORT,
secure: IS_TLS_PORT,
auth: {
user: EMAIL_USERNAME,
pass: EMAIL_PASSWORD,
@@ -67,7 +72,7 @@ function sendEmailAlert(event, data) {
function sendEmail(subject, body) {
transport
.sendMail({
from: EMAIL_USERNAME,
from: EMAIL_FROM,
to: EMAIL_SEND_TO,
subject: subject,
html: body,