mediasoup-demo es un código de muestra para una aplicación de videoconferencia implementada usando la biblioteca mediasoup.
La aplicación de ejemplo mediasoup-demo proporciona una solución de videoconferencia basada en WebRTC, que incluye gestión de salas, gestión de transmisión de medios, transmisión de red y funciones de códec de audio y vídeo. También proporciona ejemplos de código de front-end y back-end para facilitar el aprendizaje y la referencia. .
Entre ellos, mediasoup es un servidor de medios y señalización WebRTC de código abierto para crear aplicaciones de comunicación de audio y video en tiempo real.
2. estructura de código mediasoup-demo
El diagrama de estructura del código mediasoup-demo es el siguiente:
Las funciones de cada directorio o archivo son las siguientes:
Tabla de contenido
directorio o archivo del siguiente nivel
efecto
aplicación
codigo del cliente
locutores
transmitir, empujar o tirar
servidor
Demostración del servidor
servidor.js
Programa principal de demostración del servidor
config.js
archivo de configuración
certificado
certificado y clave
conectar.js
Encapsule el siguiente archivo interactiveClient.js
liberación
Archivos de biblioteca utilizados por server.js
Registrador.js
registro de impresión
Habitación.js
Gestión de salas y procesamiento de señalización.
clienteinteractivo.js
Cliente de consulta de información interna en tiempo de ejecución
servidorinteractivo.js
Servidor de consulta de información interna en tiempo de ejecución
Concéntrese en el contenido del archivo de directorio del servidor.
3. Análisis del código del servidor de demostración de Mediasoup
El directorio del servidor en el proyecto mediasoup-demo implementa las funciones de back-end de la aplicación de videoconferencia, incluida la integración con mediasoup, la comunicación WebSocket, la gestión de salas, el registro y otras funciones.
1. Análisis de código de config.js
config.js es un archivo de configuración, que se utiliza para definir parámetros como la configuración de mediasoup y el puerto del servidor.
El archivo de configuración es el siguiente:
/**
* IMPORTANT (PLEASE READ THIS):
*
* This is not the "configuration file" of mediasoup. This is the configuration
* file of the mediasoup-demo app. mediasoup itself is a server-side library, it
* does not read any "configuration file". Instead it exposes an API. This demo
* application just reads settings from this file (once copied to config.js) and
* calls the mediasoup API with those settings when appropriate.
*/const os =require('os');
module.exports ={
// Listening hostname (just for `gulp live` task).domain: process.env.DOMAIN||'localhost',// Signaling settings (protoo WebSocket server and HTTP API server).https://{
listenIp:'0.0.0.0',// NOTE: Don't change listenPort (client app assumes 4443).listenPort: process.env.PROTOO_LISTEN_PORT||4443,// NOTE: Set your own valid certificate files.tls:{
cert: process.env.HTTPS_CERT_FULLCHAIN||`${
__dirname}/certs/fullchain.pem`,key: process.env.HTTPS_CERT_PRIVKEY||`${
__dirname}/certs/privkey.pem`}},// mediasoup settings.mediasoup:{
// Number of mediasoup workers to launch.numWorkers: Object.keys(os.cpus()).length,// mediasoup WorkerSettings.// See https://mediasoup.org/documentation/v3/mediasoup/api/#WorkerSettingsworkerSettings:{
logLevel:'warn',logTags:['info','ice','dtls','rtp','srtp','rtcp','rtx','bwe','score','simulcast','svc','sctp'],rtcMinPort: process.env.MEDIASOUP_MIN_PORT||40000,rtcMaxPort: process.env.MEDIASOUP_MAX_PORT||49999},// mediasoup Router options.// See https://mediasoup.org/documentation/v3/mediasoup/api/#RouterOptionsrouterOptions:{
mediaCodecs:[{
kind:'audio',mimeType:'audio/opus',clockRate:48000,channels:2},{
kind:'video',mimeType:'video/VP8',clockRate:90000,parameters:{
'x-google-start-bitrate':1000}},{
kind:'video',mimeType:'video/VP9',clockRate:90000,parameters:{
'profile-id':2,'x-google-start-bitrate':1000}},{
kind:'video',mimeType:'video/h264',clockRate:90000,parameters:{
'packetization-mode':1,'profile-level-id':'4d0032','level-asymmetry-allowed':1,'x-google-start-bitrate':1000}},{
kind:'video',mimeType:'video/h264',clockRate:90000,parameters:{
'packetization-mode':1,'profile-level-id':'42e01f','level-asymmetry-allowed':1,'x-google-start-bitrate':1000}}]},// mediasoup WebRtcServer options for WebRTC endpoints (mediasoup-client,// libmediasoupclient).// See https://mediasoup.org/documentation/v3/mediasoup/api/#WebRtcServerOptions// NOTE: mediasoup-demo/server/lib/Room.js will increase this port for// each mediasoup Worker since each Worker is a separate process.webRtcServerOptions:{
listenInfos:[{
protocol:'udp',ip: process.env.MEDIASOUP_LISTEN_IP||'0.0.0.0',announcedIp: process.env.MEDIASOUP_ANNOUNCED_IP,port:44444},{
protocol:'tcp',ip: process.env.MEDIASOUP_LISTEN_IP||'0.0.0.0',announcedIp: process.env.MEDIASOUP_ANNOUNCED_IP,port:44444}],},// mediasoup WebRtcTransport options for WebRTC endpoints (mediasoup-client,// libmediasoupclient).// See https://mediasoup.org/documentation/v3/mediasoup/api/#WebRtcTransportOptionswebRtcTransportOptions:{
// listenIps is not needed since webRtcServer is used.// However passing MEDIASOUP_USE_WEBRTC_SERVER=false will change it.listenIps:[{
ip: process.env.MEDIASOUP_LISTEN_IP||'0.0.0.0',announcedIp: process.env.MEDIASOUP_ANNOUNCED_IP}],initialAvailableOutgoingBitrate:1000000,minimumAvailableOutgoingBitrate:600000,maxSctpMessageSize:262144,// Additional options that are not part of WebRtcTransportOptions.maxIncomingBitrate:1500000},// mediasoup PlainTransport options for legacy RTP endpoints (FFmpeg,// GStreamer).// See https://mediasoup.org/documentation/v3/mediasoup/api/#PlainTransportOptionsplainTransportOptions:{
listenIp:{
ip: process.env.MEDIASOUP_LISTEN_IP||'0.0.0.0',announcedIp: process.env.MEDIASOUP_ANNOUNCED_IP},maxSctpMessageSize:262144}}};
Comentario de información de configuración de config.js:
campo principal
subcampo
efecto
https
escucharip
La dirección IP en la que escucha el servidor
Puerto de escucha
El puerto en el que escucha el servidor
mediasopa
configuración del trabajador
Parámetros de configuración del trabajador de mediasoup, incluido el número de trabajadores, la ruta del archivo del proceso del trabajador, logLevel, etc.
Opciones de enrutador
Parámetros de configuración del enrutador de mediasoup, incluidos los parámetros de configuración del códec de medios
webRtcServerOptions
Parámetros de configuración de WebRtcServer de Mediasoup, incluidos el protocolo de escucha, la IP y el puerto
webRtcTransportOptions
Parámetros de configuración de WebRtcTransport de mediasoup, incluidos los puertos de escucha para el reenvío de UDP/TCP, ancho de banda máximo, paquetes de datos máximos, etc.
opciones de transporte simple
Parámetros de configuración de PlainTransport de mediasoup, incluido el puerto de escucha para el reenvío de UDP/TCP, el ancho de banda máximo, el paquete de datos máximo, etc.
server.js es la parte central de la aplicación mediasoup-demo, responsable de iniciar y administrar varios componentes y manejar la transmisión y el procesamiento de datos de audio y video.
1. La lógica principal de server.js
Cargue el archivo de configuración: lea los parámetros de configuración en el archivo config.js, incluidos los números de puerto de los servidores HTTP y WebSocket, la cantidad de procesos de Mediasoup Worker, etc.
Iniciar servidor HTTP: cree un servidor HTTP y escuche las solicitudes en el puerto especificado.
El servidor HTTP se utiliza principalmente para proporcionar recursos estáticos, como páginas frontales, archivos CSS y JS, etc.
Inicie el servidor WebSocket: cree un servidor WebSocket y escuche las solicitudes de conexión en el puerto especificado.
El servidor WebSocket se utiliza para procesar la transmisión de datos de audio y video en tiempo real.
Inicie el proceso de mediasoup Worker: de acuerdo con el parámetro worker.numWorkers en el archivo de configuración, cree una cantidad específica de procesos de mediasoup Worker.
Cada proceso Worker es responsable de administrar los objetos de enrutador y los objetos de transporte de mediasoup, así como de manejar el reenvío y el procesamiento de transmisiones de audio y video.
Manejar la conexión WebSocket: cuando se establece una nueva conexión WebSocket, server.js creará un nuevo objeto de enrutador de mediasoup y lo vinculará a un proceso de trabajo de mediasoup especificado.
Al mismo tiempo, server.js creará un objeto de transporte para la conexión WebSocket y lo vinculará al objeto de enrutador mediasoup correspondiente.
De esta forma, el cliente WebSocket puede transmitir y procesar flujos de audio y video a través del objeto Transport y el objeto Router de mediasoup.
Manejar solicitudes HTTP: cuando llega una solicitud HTTP, server.js devolverá el recurso estático correspondiente de acuerdo con la ruta de la solicitud.
Por ejemplo, la página index.html se devuelve cuando se solicita la ruta "/".
Manejo de errores: server.js también es responsable de manejar varios errores, incluidos los errores del servidor HTTP y WebSocket, los errores del proceso Mediasoup Worker y los errores del cliente WebSocket, etc.
Cuando ocurre un error, server.js registrará la información del error en el archivo de registro e intentará restaurar o reiniciar el servicio o proceso relacionado.
2. Análisis de código específico de server.js
server.js en el directorio del servidor es el archivo de entrada de la aplicación del servidor, responsable de iniciar la aplicación, crear servidores HTTP y WebSocket y administrar el proceso de trabajo de mediasoup.
La función run() es la función de entrada server.js:
En mediasoup-demo, mediasoup Worker es la parte central de mediasoup.Es responsable de procesar transmisiones de audio y video y administrar los recursos subyacentes de mediasoup.
Dado que la creación y destrucción de trabajadores de mediasoup lleva mucho tiempo, se crearán varios trabajadores de mediasoup en mediasoup-demo para mejorar la capacidad de procesamiento del sistema.
En la función runMediasoupWorkers(), se pueden crear, administrar y monitorear múltiples trabajadores de mediasoup para garantizar el funcionamiento normal de mediasoup-demo.
El código específico y los comentarios son los siguientes:
/**
* Launch as many mediasoup Workers as given in the configuration file.
*/asyncfunctionrunMediasoupWorkers(){
// 从配置文件中获取mediasoup的配置项numWorkers,即需要启动的mediasoup Worker数量。const{
numWorkers }= config.mediasoup;
logger.info('running %d mediasoup Workers...', numWorkers);// 使用mediasoup.createWorker()创建指定数量的mediasoup Worker,并将其存储到全局数组mediasoupWorkers中。for(let i =0; i < numWorkers;++i){
const worker =await mediasoup.createWorker({
logLevel: config.mediasoup.workerSettings.logLevel,logTags: config.mediasoup.workerSettings.logTags,rtcMinPort:Number(config.mediasoup.workerSettings.rtcMinPort),rtcMaxPort:Number(config.mediasoup.workerSettings.rtcMaxPort)});// 每个mediasoup Worker创建成功后,为其添加一个died事件监听器,当Worker死亡时自动退出进程。// 该事件监听器通过setTimeout()设置了一个2秒的定时器,定时器到期后退出进程。
worker.on('died',()=>{
logger.error('mediasoup Worker died, exiting in 2 seconds... [pid:%d]', worker.pid);setTimeout(()=> process.exit(1),2000);});
mediasoupWorkers.push(worker);// 对于每个mediasoup Worker,如果配置文件中的MEDIASOUP_USE_WEBRTC_SERVER环境变量的值不为false,则在其中创建一个WebRtcServer。// Create a WebRtcServer in this Worker.if(process.env.MEDIASOUP_USE_WEBRTC_SERVER!=='false'){
// Each mediasoup Worker will run its own WebRtcServer, so those cannot// share the same listening ports. Hence we increase the value in config.js// for each Worker.// 为了避免多个mediasoup Worker之间端口冲突,配置文件中WebRtcServer的监听端口需要逐个增加,这样每个mediasoup Worker创建的// WebRtcServer监听端口才不会相同。因此,在为每个mediasoup Worker创建WebRtcServer时,会逐个增加WebRtcServer配置中的端口号。const webRtcServerOptions = utils.clone(config.mediasoup.webRtcServerOptions);const portIncrement = mediasoupWorkers.length -1;for(const listenInfo of webRtcServerOptions.listenInfos){
listenInfo.port += portIncrement;}const webRtcServer =await worker.createWebRtcServer(webRtcServerOptions);//每个mediasoup Worker创建的WebRtcServer将被存储到其appData属性中。
worker.appData.webRtcServer = webRtcServer;}// Log worker resource usage every X seconds.// 每个mediasoup Worker将会定时记录其资源使用情况,并使用setInterval()函数设置一个时间间隔,// 即每隔一段时间输出一次mediasoup Worker的资源使用情况。setInterval(async()=>{
const usage =await worker.getResourceUsage();
logger.info('mediasoup Worker resource usage [pid:%d]: %o', worker.pid, usage);},120000);}}
2. Análisis de la función mediasoup.createWorker()
El método mediasoup.createWorker() en la función runMediasoupWorkers() es un método asíncrono proporcionado por la biblioteca mediasoup, que se utiliza para crear una instancia de mediasoup Worker. La implementación específica se encuentra en el código node/src/index.ts de mediasoup proyecto.
En la versión mediasoup-demo v3, el método mediasoup.createWorker() se llama varias veces, cada llamada creará una instancia de Worker y empujará la instancia a la matriz de variable global mediasoupWorkers.
En la implementación de la versión v3, cada instancia de Worker tendrá su propia instancia de enrutador mediasoup independiente, para garantizar que las diferentes salas utilicen instancias de enrutador independientes para el procesamiento de medios, mejorando la escalabilidad y la estabilidad del sistema.
Al mismo tiempo, cada instancia de Worker creará una instancia de WebRtcServer en su puerto correspondiente para administrar la conexión del cliente WebRTC.
El siguiente es un análisis detallado del método mediasoup.createWorker():
options: Tipo de objeto, indicando opciones para crear instancias de Worker. Las opciones incluyen:
logLevel: tipo de cadena, que indica el nivel de registro de la instancia de Worker. El valor predeterminado es advertir.
logTags: tipo de matriz, que indica las etiquetas de registro de la instancia de Worker. El valor predeterminado es ['info', 'ice', 'dtls', 'rtp', 'srtp', 'rtcp', 'rtx', 'bwe', 'score', 'simulcast', 'svc'].
rtcMinPort: Tipo de número, que indica el puerto UDP mínimo utilizado por la instancia de Worker. El valor predeterminado es 10000.
rtcMaxPort: Tipo de número, que indica el puerto UDP máximo utilizado por la instancia de Worker. El valor predeterminado es 59999.
dtlsCertificateFile y dtlsPrivateKeyFile son rutas a archivos de certificados y claves privadas para DTLS.
Si las rutas a estos archivos no están configuradas, mediasoup utilizará el certificado predeterminado y la clave privada.
libwebrtcFieldTrials es una característica experimental en la biblioteca Google WebRTC.
appData se puede usar para almacenar datos de aplicaciones asociados con instancias de trabajo.
Si se establece appData, debe ser un objeto. De forma predeterminada, appData no está definido.
Valor devuelto: tipo de promesa, que representa el objeto de instancia de Worker creado.
Entre ellos, el nuevo trabajador creará un proceso de trabajo del trabajador y establecerá un canal IPC entre el proceso de trabajo y el proceso principal, para realizar la comunicación entre procesos.
Worker se utiliza para manejar las funciones principales de mediasoup, como la transmisión RTP, la gestión de salas, etc.
3. Análisis de la función runHttpsServer()
La función principal de la función runHttpsServer() es crear y ejecutar un servidor web basado en HTTPS y escuchar la dirección IP y el puerto especificados en el archivo de configuración.
El código específico y los comentarios son los siguientes:
/**
* Create a Node.js HTTPS server. It listens in the IP and port given in the
* configuration file and reuses the Express application as request listener.
*/asyncfunctionrunHttpsServer(){
logger.info('running an HTTPS server...');// HTTPS server for the protoo WebSocket server.// 定义了tls的对象,用于存储HTTPS服务器所需的TLS证书和密钥const tls ={
cert: fs.readFileSync(config.https.tls.cert),key: fs.readFileSync(config.https.tls.key)};// 创建一个HTTPS服务器实例,并将tls对象和expressApp作为参数传递进去。
httpsServer = https.createServer(tls, expressApp);// 监听HTTPS服务器的端口和IP地址,并返回一个Promise。awaitnewPromise((resolve)=>{
httpsServer.listen(Number(config.https.listenPort), config.https.listenIp, resolve);});}
4. Análisis de la función runProtooWebSocketServer()
La función runProtooWebSocketServer() se usa principalmente para iniciar un servidor WebSocket para permitir que el navegador se conecte al servidor a través de WebSocket.
/**
* Create a protoo WebSocketServer to allow WebSocket connections from browsers.
*/asyncfunctionrunProtooWebSocketServer(){
logger.info('running protoo WebSocketServer...');// Create the protoo WebSocket server.// 创建一个 WebSocket 服务器 protooWebSocketServer
protooWebSocketServer =newprotoo.WebSocketServer(httpsServer,{
maxReceivedFrameSize:960000,// 960 KBytes.maxReceivedMessageSize:960000,fragmentOutgoingMessages:true,fragmentationThreshold:960000});// Handle connections from clients.// 注册 connectionrequest 事件的监听器,有新的 WebSocket 连接请求时被触发。
protooWebSocketServer.on('connectionrequest',(info, accept, reject)=>{
// The client indicates the roomId and peerId in the URL query.// 在监听器中,从连接请求的 URL 中解析出房间 ID 和 peer ID,如果解析失败或者没有这些参数,就拒绝连接请求。const u = url.parse(info.request.url,true);const roomId = u.query['roomId'];const peerId = u.query['peerId'];if(!roomId ||!peerId){
reject(400,'Connection request without roomId and/or peerId');return;}// 从URL中解析出消费者实例的数量 consumerReplicas,如果解析失败则将其设置为默认值 0。let consumerReplicas =Number(u.query['consumerReplicas']);if(isNaN(consumerReplicas)){
consumerReplicas =0;}
logger.info('protoo connection request [roomId:%s, peerId:%s, address:%s, origin:%s]',
roomId, peerId, info.socket.remoteAddress, info.origin);// Serialize this code into the queue to avoid that two peers connecting at// the same time with the same roomId create two separate rooms with same// roomId.// 为了避免同时有两个连接请求使用相同的roomId创建两个不同的房间,使用了一个queue队列将代码序列化。// 在队列中,调用 getOrCreateRoom() 函数获取或创建一个房间,并返回一个 Room 实例。// 如果房间创建或加入失败,就会在 catch 代码块中将错误信息返回给客户端,并拒绝连接请求。
queue.push(async()=>{
const room =awaitgetOrCreateRoom({
roomId, consumerReplicas });// Accept the protoo WebSocket connection.// 如果任务执行成功,使用 accept() 接受 WebSocket 连接const protooWebSocketTransport =accept();
room.handleProtooConnection({
peerId, protooWebSocketTransport });}).catch((error)=>{
logger.error('room creation or room joining failed:%o', error);reject(error);});});}
3. Análisis de código de Room.js
Room.js implementa la lógica de gestión de una sola sala en la aplicación, y se encarga de gestionar una serie de operaciones como la entrada/salida de miembros de la sala, la creación y gestión de productores/consumidores, etc.
1. Análisis de código específico de Room.js
1. análisis de la función create()
La función create() crea una nueva instancia de Room.
El código específico y los comentarios son los siguientes:
/**
* Factory function that creates and returns Room instance.
*
* @async
*
* @param {mediasoup.Worker} mediasoupWorker - The mediasoup Worker in which a new
* mediasoup Router must be created.
* @param {String} roomId - Id of the Room instance.
*/staticasynccreate({
mediasoupWorker, roomId, consumerReplicas }){
logger.info('create() [roomId:%s]', roomId);// Create a protoo Room instance.// 创建了一个新的protoo Room实例,protoo是一种基于WebSocket的信令协议,用于在客户端和服务端之间传递信令消息。const protooRoom =newprotoo.Room();// Router media codecs.//根据配置文件中的mediasoup router选项,使用mediasoup worker创建一个mediasoup Router实例const{
mediaCodecs }= config.mediasoup.routerOptions;// Create a mediasoup Router.const mediasoupRouter =await mediasoupWorker.createRouter({
mediaCodecs });// Create a mediasoup AudioLevelObserver.// 使用mediasoup Router实例,创建一个mediasoup AudioLevelObserver实例,用于观察媒体流中的音频级别。// 这个观察者的作用是用来检测房间中正在说话的用户,以便对其进行相关操作,如推送媒体流等。const audioLevelObserver =await mediasoupRouter.createAudioLevelObserver({
maxEntries:1,threshold:-80,interval:800});// Create a mediasoup ActiveSpeakerObserver.// 使用mediasoup Router实例上,创建一个mediasoup ActiveSpeakerObserver实例,用于观察房间中当前发言者的情况。// 这个观察者的作用是用来检测房间中的活跃发言者,以便在客户端中实时显示。const activeSpeakerObserver =await mediasoupRouter.createActiveSpeakerObserver();// 最后,使用同样的mediasoup Router实例,创建一个Bot实例,Bot是一个虚拟的用户,用于在房间中扮演一个音频流的源。// 它的主要作用是在测试和演示中使用,例如在没有实际用户的情况下测试房间的性能等。const bot =await Bot.create({
mediasoupRouter });// 最终返回一个新的Room实例,包含上述创建的protoo Room实例、mediasoup Router实例、以及用于观察音频级别和活跃发言者的mediasoup观察者实例等信息。returnnewRoom({
roomId,
protooRoom,webRtcServer: mediasoupWorker.appData.webRtcServer,
mediasoupRouter,
audioLevelObserver,
activeSpeakerObserver,
consumerReplicas,
bot
});}
2. Análisis de la función handleProtooConnection()
La función handleProtooConnection() se usa para administrar la conexión con el cliente, garantizar que cada conexión sea única y pueda manejar la solicitud enviada por el cliente y devolver el resultado correspondiente.
Después de que la función runProtooWebSocketServer() en server.js crea un servidor WebSocket, el servidor registrará un oyente para el evento de solicitud de conexión, que se activará cuando haya una nueva solicitud de conexión WebSocket y eventualmente llamará a la función handleProtooConnection().
El código específico y los comentarios son los siguientes:
/**
* Called from server.js upon a protoo WebSocket connection request from a
* browser.
*
* @param {String} peerId - The id of the protoo peer to be created.
* @param {Boolean} consume - Whether this peer wants to consume from others.
* @param {protoo.WebSocketTransport} protooWebSocketTransport - The associated
* protoo WebSocket transport.
*/handleProtooConnection({
peerId, consume, protooWebSocketTransport }){
// 为了确保每个连接都是唯一的,根据peerId查找是否已经存在同名的protoo Peer对象,如果存在,则关闭该protoo Peer对象。const existingPeer =this._protooRoom.getPeer(peerId);if(existingPeer){
logger.warn('handleProtooConnection() | there is already a protoo Peer with same peerId, closing it [peerId:%s]',
peerId);
existingPeer.close();}// 如果不存在同名的protoo Peer对象,则创建一个新的protoo Peer对象。// 并通过peer.data对象存储相关数据,如是否已经加入房间、用户名称等等。// 同时,也创建了几个map对象,用于存储房间中的生产者、消费者、数据生产者和数据消费者对象。let peer;// Create a new protoo Peer with the given peerId.try{
peer =this._protooRoom.createPeer(peerId, protooWebSocketTransport);}catch(error){
logger.error('protooRoom.createPeer() failed:%o', error);}// Use the peer.data object to store mediasoup related objects.// Not joined after a custom protoo 'join' request is later received.
peer.data.consume = consume;
peer.data.joined =false;
peer.data.displayName =undefined;
peer.data.device =undefined;
peer.data.rtpCapabilities =undefined;
peer.data.sctpCapabilities =undefined;// Have mediasoup related maps ready even before the Peer joins since we// allow creating Transports before joining.
peer.data.transports =newMap();
peer.data.producers =newMap();
peer.data.consumers =newMap();
peer.data.dataProducers =newMap();
peer.data.dataConsumers =newMap();// 监听protoo Peer对象的request事件,当有请求到达时,执行_handleProtooRequest函数来处理请求,并返回相应的结果。// 如果出现异常,则通过reject函数返回错误信息。
peer.on('request',(request, accept, reject)=>{
logger.debug('protoo Peer "request" event [method:%s, peerId:%s]',
request.method, peer.id);this._handleProtooRequest(peer, request, accept, reject).catch((error)=>{
logger.error('request failed:%o', error);reject(error);});});// 当一个protoo连接关闭时,触发protoo Peer对象的close事件。
peer.on('close',()=>{
// 首先判断房间是否已经关闭,如果已经关闭则直接返回,避免重复关闭。if(this._closed)return;
logger.debug('protoo Peer "close" event [peerId:%s]', peer.id);// If the Peer was joined, notify all Peers.// 如果该Peer已经加入房间,通知所有其他Peers该Peer已经关闭。if(peer.data.joined){
for(const otherPeer ofthis._getJoinedPeers({
excludePeer: peer })){
otherPeer.notify('peerClosed',{
peerId: peer.id }).catch(()=>{
});}}// Iterate and close all mediasoup Transport associated to this Peer, so all// its Producers and Consumers will also be closed.// 遍历所有该Peer创建的Transport并关闭,这样该Peer创建的所有Producers和Consumers都将被关闭。for(const transport of peer.data.transports.values()){
transport.close();}// If this is the latest Peer in the room, close the room.// 判断该Peer是否是房间中的最后一个Peer,如果是,则关闭整个房间。if(this._protooRoom.peers.length ===0){
logger.info('last Peer in the room left, closing the room [roomId:%s]',this._roomId);this.close();}});}
3. Análisis de la función _handleProtooRequest()
La función _handleProtooRequest es para manejar el mensaje enviado por el cliente a través de la conexión WebSocket.
La función _handleProtooRequest se define de la siguiente manera: