the benefit of protoo

What is the benefit of using protoo for signaling instead socket.io ?
iam new to the area of this signaling and i notice some bug happen a lot more often when using websocket like doublicat the messages.

You can use whatever you want. The mediasoup demo is not a production grade application.

Preformatted text``Preformatted text``Preformatted textHi @ibc i did use protoo along side mediasoup to develop a videoconferencing app all in node
i actually use the official demo server side code, but on the client side, instead of using react as they did, i’m still using node. i actually succeeded writing the code with no error, now the problem is i am rightfully producing and consuming media, but the consume media is not displaying on the video element, though the video element is created when consuming but no video is been displayed. i dont know if you can help me out

this is the clientcode


import { Peer, WebSocketTransport } from ‘protoo-client’;
import mediasoupClient, { Device } from ‘mediasoup-client’;

document.addEventListener(‘DOMContentLoaded’, () => {
var device
let rtpCapabilities
let producerTransport
let recvTransport
let consumerTransports =
let producer
let consumer
let deviceName
// Force VP8 codec for sending.
// @type {Boolean}
let forceVP8 = true;

	// Force H264 codec for sending.
	// @type {Boolean}
let forceH264 = true;

	// Force VP9 codec for sending.
	// @type {Boolean}
let forceVP9 = true;

let consumers = new Map(); // Add this line to store consumers
const joinForm = document.getElementById(‘joinForm’);

const peerList = document.getElementById(‘peerList’);

let peer;

joinForm.addEventListener(‘submit’, async (event) => {
event.preventDefault();
document.getElementById(‘joinFormContainer’).style.display = ‘none’;
document.getElementById(‘videoContainer’).style.display = ‘block’;
const localVideo = document.getElementById(‘localvideo’)

const displayName = document.getElementById('displayName').value;

const roomId = '3763';
const serverAddress = 'localhost:4443';
const peerId = `${displayName}1242`;
const protooUrl = `wss://${serverAddress}/?roomId=${roomId}&peerId=${peerId}`;
console.log(displayName)
try {
  const protooTransport = new WebSocketTransport(protooUrl);
  peer = new Peer(protooTransport);

  peer.on('open', () => {
    console.log('Peer connected');
    joinRoom(displayName, deviceName);
  });

  peer.on('close', () => {
    console.log('Peer disconnected');
  });

  peer.on('error', (error) => {
    console.error('Peer error:', error);
  });

  // Handle new consumer notifications
  peer.on('request', async (request, accept, reject) => {

    switch (request.method) {
      case 'newConsumer':
        {
          const {
            peerId,
            producerId,
            id,
            kind,
            rtpParameters,
            type,
            appData,
            producerPaused
          } = request.data;

          try {

            const consumer = await recvTransport.consume({
              id,
              producerId,
              kind,
              rtpParameters,
              type,
              appData: { ...appData, peerId }
            });

            // Store the Consumer in the local state
            consumerTransports.push(consumer);
            consumers.set(consumer.id, consumer);

            console.log('Consumed media from producer', producerId);


            // Set up event handlers for the Consumer
            consumer.on('transportclose', () => {
              console.log('Consumer transport closed');
              consumers.delete(consumer.id);
              consumerTransports = consumerTransports.filter(c => c.id !== consumer.id);
            });
            const { spatialLayers, temporalLayers } =
              mediasoupClient.parseScalabilityMode(
                consumer.rtpParameters.encodings[0].scalabilityMode
              );
              
              const remoteVideo = document.createElement('video');
              const stream = new MediaStream();
              if(consumer.track){
                console.log('there is a track attached to this consumer', consumer.track)
              }else{
                console.log('consumer does not have a track')
              }
              stream.addTrack(consumer.track);
              // remoteVideo.srcObject = new MediaStream([consumer.track]);
              remoteVideo.srcObject = stream
              remoteVideo.autoplay = true;
              remoteVideo.controls = true
              remoteVideo.id = consumer.id
              remoteVideo.playsInline = true;
              remoteVideo.muted = true; // Ensure it is not muted
              document.getElementById('remoteVideos').appendChild(remoteVideo);

              console.log('New consumer added:', consumer.id, [consumer.track]);


           

            accept();
            
      // Resume the consumer
      await consumer.resume();

      console.log('New consumer added after resume:', consumer.id, consumer.track.type);

      // Log when the video actually starts playing
      remoteVideo.addEventListener('playing', () => {
        console.log('Remote video started playing:', consumer.id);
        remoteVideo.muted = false; // Unmute after playback starts
      });
           

          }
          catch (error) {
            console.log('"newConsumer" request failed:%o', error);

          }

          break;
        }
        case 'resumeConsumer':
        {
          const { consumerId } = request.data;
          console.log('consumerResumed', request.data)
          const consumer = consumers.get(consumerId)
          if (!consumer)
            break;
          consumer.resume();
          break
        }

    }
  });

  peer.on('notification', (notification) => {
    console.log('Received notification:', notification);
    switch (notification.method) {
      case 'newPeer':
        {
          const peer = notification.data;
          console.log('newPeer', peer)
          break
        }
      case 'producerScore':
        {
          const { producerId, score } = notification.data;

          console.log('producerScore', notification.data)

          break;
        }
      case 'consumerResumed':
        {
          const { consumerId } = notification.data;
          console.log('consumerResumed', notification.data)
          const consumer = consumers.get(consumerId)
          if (!consumer)
            break;
          consumer.resume();
          break
        }

      case 'mediasoup-version':
        {
          const { version } = notification.data;
          console.log(version, notification.data)

          break;
        }

      case 'consumerResumed':
        {
          const { consumerId } = notification.data
          const consumer = consumers.get(consumerId);
          if (!consumer)
            break;
          consumer.resume();
        }
      // Handle other notifications
    }
  });

} catch (error) {
  console.error('Failed to create peer:', error);
}

});

async function joinRoom(displayName, deviceInput) {

try {

  deviceName = mediasoupClient.detectDevice();
  if (deviceName) {
    console.log("detected handler: %s", deviceName);
  } else {
    console.warn("no suitable handler found for current browser/device");
  }

  // Properly initialize the device from mediasoup-client
  device = new mediasoupClient.Device({
    handlerName: deviceName
  });

  // Ensure the RTP capabilities are loaded properly before proceeding
  const routerRtpCapabilities = await peer.request('getRouterRtpCapabilities');


  await device.load({ routerRtpCapabilities });

  console.log('Router RTP Capabilities loaded:', device.rtpCapabilities);

  // Create mediasoup Device
  await createDevice(deviceInput);

  const { peers } = await peer.request('join', {
    displayName: displayName,
    device: deviceName,
    rtpCapabilities: device.rtpCapabilities, // Add this line
    sctpCapabilities: device.sctpCapabilities
  });

  // For each existing peer, create consumers for their producers
  for (const existingPeer of peers) {

    console.log('producers,', existingPeer.producer)
    // await consumeProducer(producer.id);

  }

  console.log('Joined room. Peers:', peers);
  updatePeerList(peers);



  //await createRecvTransport();
  // Start producing media
  await produce();



} catch (error) {
  console.error('Failed to join room:', error);
}

}

function updatePeerList(peers) {
peerList.innerHTML = ‘’;
peers.forEach(peer => {
const li = document.createElement(‘li’);
li.textContent = ${peer.displayName} (${peer.device});
li.className = ‘list-group-item’;
console.log(peer.rtpCapabilities)
peerList.appendChild(li);
});
}

//A device is an endpoint connecting to a Router on the server side to send/recive media
const createDevice = async (deviceInput) => {
try {
console.log(‘Device RTP Capabilities’, device.rtpCapabilities)
deviceInput = deviceName

  // Ensure the device can produce audio and video
  if (!device.canProduce('video') || !device.canProduce('audio')) {
    throw new Error('Device cannot produce media (audio/video). Check capabilities.');
  }


  console.log('Device loaded successfully');
  // once the device loads, create transport
  await createSendTransport()
  await createRecvTransport()


} catch (error) {
  console.log(error)
  if (error.name === 'UnsupportedError')
    console.warn('browser not supported')
}

}

async function createSendTransport() {
try {
// 1. Request transport parameters from the server
const transportParams = await peer.request(‘createWebRtcTransport’, {
forceTcp: false,
producing: true,
consuming: false,
sctpCapabilities: device.sctpCapabilities,
});
let track

  const { id, iceParameters, iceCandidates, dtlsParameters, sctpParameters } = transportParams

  // Create a new mediasoup-client Transport
  // 2. Create a send transport
  producerTransport = device.createSendTransport({
    id,
    iceParameters,
    iceCandidates,
    dtlsParameters: {
      ...dtlsParameters, role: 'auto'
    },
    sctpParameters,
    iceServers: []
  });


  // 3. Set up transport event handlers
  producerTransport.on('connect', async ({ dtlsParameters, iceParameters, appData }, callback, errback) => {
    try {
      const response = await peer.request('connectWebRtcTransport', {
        transportId: producerTransport.id,
        dtlsParameters,
        iceParameters
      });
      console.log('Producer transport connected successfully');
      callback(response);
    } catch (error) {
      console.error('Producer transport connection error:', error);
      await errback(error);
    }
  });

  producerTransport.on('produce', async ({ kind, rtpParameters, appData }, callback, errback) => {
    try {
      const { id } = await peer.request('produce', {
        transportId: producerTransport.id,
        kind,
        rtpParameters,
        appData
      });
      callback({ id });
    } catch (error) {
      await errback(error);
    }
  });
} catch (error) {
  console.log('Producer transport error');
  console.log(error)
}

}

async function produce() {
// Produce our webcam video.

try {
  const stream = await navigator.mediaDevices.getUserMedia({
    video: true, audio: true
  })
  let encodings;
		let codec;
		const codecOptions =
		{
			videoGoogleStartBitrate : 1000
		};
  encodings =[
    {
      scaleResolutionDownBy:1,
      maxBitrate: 5000000,
      scalabilityMode:'L1T3'
    }
  ]
  encodings.unshift(
    {
      scaleResolutionDownBy:2,
      maxBitrate:1000000,
      scalabilityMode:'L1T3'
    }
  )
  codec = device.rtpCapabilities.codecs
  .find((c)=>c.mimeType.toLowerCase()==='video/vp8')
  if (!codec)
			{
				console.log('desired VP8 codec+configuration is not supported');
      codec = device.rtpCapabilities.codecs
				.find((c) => c.mimeType.toLowerCase() === 'video/h264');

			}
  const videoTrack = stream.getVideoTracks()[0];
  const audioTrack = stream.getAudioTracks()[0];
  const producer = await producerTransport.produce({ track: videoTrack, encodings,codecOptions,codec });
  // await producerTransport.produce({
  //   track: audioTrack, encodings: [{ maxBitrate: 1000000 }],
  //   codecOptions: { videoGoogleStartBitrate: 1000 }
  // });
  console.log('production going on,', producer)
  producer.on('trackended', () => {
    console.log('Track ended');
  });


  localVideo.srcObject = stream
  localVideo.play();

  console.log('Started producing media');
} catch (error) {
  console.error('Failed to produce media:', error);
}

}

async function createRecvTransport() {
try {
// Request transport parameters from the server for receiving media
const transportParams = await peer.request(‘createWebRtcTransport’, {
forceTcp: false,
producing: false,
consuming: true,
sctpCapabilities: device.sctpCapabilities,
});
// Create a receiving transport
console.log(‘receiving transport:’, transportParams)
const {
id,
iceParameters,
iceCandidates,
dtlsParameters,
sctpParameters
} = transportParams;
recvTransport = device.createRecvTransport({
id,
iceParameters,
iceCandidates,
dtlsParameters: { …dtlsParameters, role: ‘auto’ },
sctpParameters,
iceServers: ,
appData: { consuming: true } // Add this line
});

  // Handle the transport connection
  recvTransport.on('connect', async ({ dtlsParameters, iceParameters }, callback, errback) => {
    try {
      const response = await peer.request('connectWebRtcTransport', {
        transportId: recvTransport.id,
        dtlsParameters,
        iceParameters
      });

      callback(response);
      console.log('Receiver transport connected successfully');
    } catch (error) {

      await errback(error);
      console.error('Receiver transport connection error:', error);
    }
  });
  // Store the transport for future use
  consumerTransports.push(recvTransport);

  // return recvTransport;
} catch (error) {
  console.error('Failed to create receive transport:', error);
}

}

async function consumeMedia(peerId, producerId, consumerId, kind, rtpParameters, type, appData) {
try {
// Create a new mediasoup-client Consumer
if (!recvTransport) {
await createRecvTransport();
}
consumer = await recvTransport.consume({
id: consumerId,
producerId,
kind,
rtpParameters,
type,
appData: { …appData, peerId }
});

  // Store the Consumer in the local state
  consumerTransports.push(consumer);

  console.log('Consumed media from producer', producerId);
} catch (error) {
  console.error('Error consuming media:', error);
  console.error('Consumer details:', { peerId, producerId, consumerId, kind });
}

}

});
````Preformatted text`

images of my console id attach to this post
![Screenshot (34)|690x387](upload://c8zjNHo2ZtG3PaL9aMKhZAdOfLo.png)
![Screenshot (35)|690x387](upload://sYi9rqBAqxejzRJZln946TtS7Vr.png)