Produce failed after upgrading from 3.12.x to 3.13.x

Producing video starts failing when upgrading mediasoup (server-side) from 3.12.x to 3.13.x. The client version seems to not affect this behavior.

My WebRtc Transport is configured as follows:

{
    listenIps: [{ ip: MY_SERVER_PUBLIC_IP, announcedIp: null }],
    enableUdp: true,
    enableTcp: true,
    preferUdp: false,
    initialAvailableOutgoingBitrate: 1000000,
}

Do I need to update something in the code? Have there been any breaking changes?

I narrowed this down to upgrading from 3.12.16 (latest 3.12.x) to 3.13.0 (or any 3.13.x). Updating the post title accordingly.

“Producing video starts failing” means absolutely nothing for us to investigate or figure out what’s going on.

The only log that I am getting is the following, on the frontend:

producerTransport.on('connectionstatechange', (state) => {

with state set to failed.

I also get “ICE failed, please add a STUN or TURN” on the browser console (it’s a browser message).

There is no crash happening on the backend, no error being thrown and no error being logged on the BE.

producerTransport.on("produce", (params, callback, error) gets called with the following params, before connectionstatechange going to failed:

{
  "kind": "video",
  "rtpParameters": {
    "mid": "0",
    "codecs": [
      {
        "mimeType": "video/VP8",
        "payloadType": 120,
        "clockRate": 90000,
        "parameters": {
          "max-fs": 12288,
          "max-fr": 60
        },
        "rtcpFeedback": [
          {
            "type": "nack",
            "parameter": ""
          },
          {
            "type": "nack",
            "parameter": "pli"
          },
          {
            "type": "ccm",
            "parameter": "fir"
          },
          {
            "type": "goog-remb",
            "parameter": ""
          },
          {
            "type": "transport-cc",
            "parameter": ""
          }
        ]
      },
      {
        "mimeType": "video/rtx",
        "payloadType": 124,
        "clockRate": 90000,
        "parameters": {
          "apt": 120
        },
        "rtcpFeedback": []
      }
    ],
    "headerExtensions": [
      {
        "uri": "urn:ietf:params:rtp-hdrext:sdes:mid",
        "id": 3,
        "encrypt": false,
        "parameters": {}
      },
      {
        "uri": "urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id",
        "id": 8,
        "encrypt": false,
        "parameters": {}
      },
      {
        "uri": "urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id",
        "id": 9,
        "encrypt": false,
        "parameters": {}
      },
      {
        "uri": "http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time",
        "id": 4,
        "encrypt": false,
        "parameters": {}
      },
      {
        "uri": "http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01",
        "id": 7,
        "encrypt": false,
        "parameters": {}
      },
      {
        "uri": "urn:ietf:params:rtp-hdrext:toffset",
        "id": 5,
        "encrypt": false,
        "parameters": {}
      }
    ],
    "encodings": [
      {
        "ssrc": 984485447,
        "rtx": {
          "ssrc": 2603763488
        },
        "dtx": false
      }
    ],
    "rtcp": {
      "cname": "{d853702e-07cc-4329-9764-ca8e1c92b0ff}",
      "reducedSize": true
    }
  },
  "appData": {
    "kind": "video"
  }
}

The only non-standard thing that I am doing is setting appData to { "kind": "video" }

Check and print here the iceCandidates that you pass to device.createSend/RecvTransport() in your client app.

With 3.13.x I am getting iceCandidates: [] (empty array) for both the send and recv transport on the client side.

With 3.12.x I am getting the following send and recv:

  • send:
[
  {
    "foundation": "udpcandidate",
    "ip": "192.168.1.50",
    "port": 11713,
    "priority": 1076302079,
    "protocol": "udp",
    "type": "host"
  },
  {
    "foundation": "tcpcandidate",
    "ip": "192.168.1.50",
    "port": 11730,
    "priority": 1076302079,
    "protocol": "tcp",
    "tcpType": "passive",
    "type": "host"
  }
]
  • recv:
[
  {
    "foundation": "udpcandidate",
    "ip": "192.168.1.50",
    "port": 11282,
    "priority": 1076302079,
    "protocol": "udp",
    "type": "host"
  },
  {
    "foundation": "tcpcandidate",
    "ip": "192.168.1.50",
    "port": 11631,
    "priority": 1076302079,
    "protocol": "tcp",
    "tcpType": "passive",
    "type": "host"
  }
]

I asked about iceCandidates obtained in mediasoup server side. Not sure where you are obtaining those ICE candidates from.

I mean, in mediasoup server side, once you create a WebRtcTransport, please print transport.iceCandidates (in server side).

Yes, those candidates are on the server side, printed just after createWebRtcTransport.

I am sending those back to the frontend via socket.io soon after obtaining them, therefore I get the same printout both on the backend and the frontend (I just double checked the logs on the backend to be sure).

Sorry if I haven’t been clear.

To recap: ICE candidates are empty on 3.13.x, while they are correct on 3.12.x.

The impacted code must be during or before the creation of the transport.

Here is a full printout of what I am doing before logging the ICE candidates:

const worker = await mediasoup.createWorker({
    rtcMinPort: config.rtcMinPort,
    rtcMaxPort: config.rtcMaxPort,
    logLevel: config.mediasoupLogLevel,
});

worker.on('died', () => {
    console.error('mediasoup worker died');
});

console.log('mediasoup worker running');

router = await worker.createRouter({ mediaCodecs: config.mediaCodecs });

console.log('mediasoup router online');

console.log(`mediasoup ip is ${config.ipAddress.ip}`);

if (config.ipAddress.announcedIp) {
    console.log('ip configuration is mapped behind nat');
}

And here is how I create the WebRtcTransport:

const transport = await router.createWebRtcTransport({
    listenIps: [config.ipAddress],
    enableUdp: true,
    enableTcp: true,
    preferUdp: false,
    initialAvailableOutgoingBitrate: 1000000,
});

config.ipAddress is equal to:

{ ip: 192.168.1.50, announcedIp: null }
1 Like

This makes no difference

Thank you! The following configuration seems to be working:

router.createWebRtcTransport({
    listenInfos: [
      { protocol: 'tcp', ip: '192.168.1.50', announcedAddress: '192.168.1.50' },
      { protocol: 'udp', ip: '192.168.1.50', announcedAddress: '192.168.1.50' },
    ],
    initialAvailableOutgoingBitrate: 1000000,
});

Thank you very much!

Final comment: I understand and appreciate the new listenInfos configuration, but why is listenIps still there if it doesn’t work?

It should work. I’m investigating it.

1 Like

Indeed there was a bug. Fixed here: [Node] Fix router.createWebRtcTransport() with listneIps by ibc · Pull Request #1330 · versatica/mediasoup · GitHub

2 Likes

Wow, that was only if preferUdp === false. Thank you, keep up the great work!

Yup, but BTW preferUdp was false by default so I’m amazed that nobody else reported this issue since 3.13.0.

BTW 3.13.19 has been released with the fix.

1 Like

I faced the same issue, i was using listenIps instead of listeninfos and my transport never got connected. Later i changed it to listenInfos and it got connected.

also in documentation you will find that enableUdp: true,
enableTcp: true,
preferUdp: false,
should only be used or to say will only be processed when providing a WebRtc server in the params of createWebRtcTransport

Guys, I recommend following the mediasoup GitHub project and check the new versions and the CHANGELOG. Indeed there was a bug when using listenIps and it was fixed in last version recently: