# the benefit of protoo

**URL:** <https://mediasoup.discourse.group/t/the-benefit-of-protoo/6244>\
**Category:** mediasoup-demo\
**Created:** [September 8, 2024, 3:38pm UTC](https://mediasoup.discourse.group/t/the-benefit-of-protoo/6244 "2024-09-08T15:38:44Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![musta201](https://yyz2.discourse-cdn.com/free1/user_avatar/mediasoup.discourse.group/musta201/32/2692_2.png) [@musta201](https://mediasoup.discourse.group/u/musta201)\
**Post date:** [September 8, 2024, 3:38pm UTC](https://mediasoup.discourse.group/t/the-benefit-of-protoo/6244/1 "2024-09-08T15:38:44Z")

</div>

What is the benefit of using protoo for signaling instead [socket.io](http://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.

---

<div class="post-metadata">

**Author:** ![ibc](https://yyz2.discourse-cdn.com/free1/user_avatar/mediasoup.discourse.group/ibc/32/1540_2.png) [@ibc](https://mediasoup.discourse.group/u/ibc)\
**Post date:** [September 8, 2024, 3:50pm UTC](https://mediasoup.discourse.group/t/the-benefit-of-protoo/6244/2 "2024-09-08T15:50:10Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![steadson](https://avatars.discourse-cdn.com/v4/letter/s/87869e/32.png) [@steadson](https://mediasoup.discourse.group/u/steadson)\
**Post date:** [September 24, 2024, 6:14pm UTC](https://mediasoup.discourse.group/t/the-benefit-of-protoo/6244/3 "2024-09-24T18:14:31Z")

</div>

`Preformatted text``Preformatted text``Preformatted text`Hi @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

```auto

```

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`

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

---

<div class="post-metadata">

**Author:** ![steadson](https://avatars.discourse-cdn.com/v4/letter/s/87869e/32.png) [@steadson](https://mediasoup.discourse.group/u/steadson)\
**Post date:** [September 24, 2024, 6:22pm UTC](https://mediasoup.discourse.group/t/the-benefit-of-protoo/6244/4 "2024-09-24T18:22:07Z")

</div>

![Screenshot (35)](https://global.discourse-cdn.com/free1/uploads/mediasoup/original/2X/c/cb0da41b447c27de15d2bf7d1f3c1e2bad9dccc5.png)
