Datachannel seems not to relay to other peers, despite consumer setup.

intro: Hello all, I’ve been playing with mediasoup for a year or so and thought I would ask my first official question on the forums here. Basically its “how do I server-side consume multiple producers on webrtc datachannel in the browser” but I’ll elaborate below. I’m hoping another member can answer my question so I don’t have to bother the developers too much. :wink:

setup:
3 clients – firefox, native js
–1 WebRTCPerConnections (from firefox) to mediasoup server
–1 Datachannel (id: 0) on each WebRTCPeerConnections
== All clients connect with success, “ondatachannel” is fired, and I can send and consume messages

1 server – nodejs
–1 mediasoup instance running 1 worker and 1 router.

I have an event handler for ‘newtransport’ attached to the router.
fyi: ‘transport’ and ‘producer’ are arrays of transports, and producer.id respectively.

router.observer.on("newtransport", (newTransport) => {
    console.log("Interconnecting new peer connection");
    //Consume existing peer's producers.    
    producer.forEach( (id, index) => {
        var consumerOptions = { dataProducerId: id }
        newTransport.consumeData(consumerOptions)
        .then( (newConsumer) => { console.log("New peer consuming producer " + id + " " + newConsumer.label)  });
    });

    //Make a producer, so other peers can consume this transport's output
    var producerOptions = {  sctpStreamParameters: { streamId: 0, ordered: true },
                                                     label: "AvatarMovements" }
    newTransport.produceData(producerOptions)
    .then( (newProducer) => {
        producer.push(newProducer.id);
        console.log("New transport producing as " + newProducer.id);

        //Existing peers consume the new peer's producer
        transport.forEach( (peerTransport) => {
            var consumerOptions = { dataProducerId: newProducer.id }
            peerTransport.consumeData(consumerOptions)
            .then( (newConsumer) => {
                console.log("Existing peer consuming producer "+ newProducer.id +" from new peer transport", transport, "abocve") })
            });
            transport.push(newTransport);
            //console.log(transport); 
    })
})

Client1 Signaling

OFFER: 
v=0
o=mozilla...THIS_IS_SDPARTA-68.7.0 6715870047767296198 0 IN IP4 0.0.0.0
s=-
t=0 0
a=sendrecv
a=fingerprint:sha-256 CF:C0:2C:DA:89:61:99:D8:61:DA:AC:1E:69:41:5C:12:87:EA:7A:72:91:01:D0:44:C3:BB:70:27:5A:95:C0:26
a=group:BUNDLE 0
a=ice-options:trickle
a=msid-semantic:WMS *
m=application 34762 UDP/DTLS/SCTP webrtc-datachannel
c=IN IP4 192.168.0.147
a=candidate:0 1 UDP 2122252543 192.168.0.147 34762 typ host
a=candidate:3 1 UDP 2122187007 2600:8800:7900:666:428d:5cff:febc:86c4 44004 typ host
a=candidate:6 1 TCP 2105524479 192.168.0.147 9 typ host tcptype active
a=candidate:7 1 TCP 2105458943 2600:8800:7900:666:428d:5cff:febc:86c4 9 typ host tcptype active
a=sendrecv
a=ice-pwd:a228bde5e877c0b9d44d182340e253bb
a=ice-ufrag:d4b95c6b
a=mid:0
a=setup:actpass
a=sctp-port:5000
a=max-message-size:1073741823

ANSWER:
v=0
o=mediasoup 15 0 IN IP4 168.235.79.45
s=-
t=0 0
a=group:BUNDLE 0
m=application 34762 UDP/DTLS/SCTP webrtc-datachannel
c=IN IP4 168.235.79.45
a=candidate:udpcandidate 1 UDP 1076558079 168.235.79.45 18337 typ host
a=candidate:tcpcandidate 1 TCP 1076302079 168.235.79.45 40620 typ host
a=ice-ufrag:eshnp327opg48bl8
a=ice-pwd:zlm42of4lid9p8ixkezlfdktmre2ehze
a=ice-lite
a=end-of-candidates
a=fingerprint:sha-1 37:1E:2F:18:8B:93:7E:7A:61:F3:E7:57:85:BB:31:50:FA:40:5F:DF
a=fingerprint:sha-224 D4:08:62:AA:7E:02:13:E4:8E:76:D0:5E:15:5F:5B:86:9E:B8:D8:22:7E:B7:EA:12:61:45:4F:CB
a=fingerprint:sha-256 02:A3:F2:BE:7B:12:9E:9E:79:5F:FE:26:9A:C9:DB:58:38:59:AC:12:81:4B:BE:C2:C3:99:30:18:D0:EE:80:8D
a=fingerprint:sha-384 96:E5:19:72:AD:3E:9C:F3:D9:40:A6:92:AE:2B:E9:E8:FB:92:06:2D:FE:B8:DB:61:DB:A4:74:13:EF:04:79:64:74:E7:14:D9:99:1D:6E:A7:5B:B3:E3:CD:15:C6:50:EA
a=fingerprint:sha-512 BF:9D:DA:55:76:8C:01:DB:8C:D6:DB:CD:0A:49:5D:D4:23:93:97:BA:E5:08:2E:92:9F:E1:41:75:85:4C:42:93:08:0E:40:B1:65:F2:6B:45:CF:E2:3D:28:DA:92:CC:52:44:84:73:65:60:40:E5:47:3C:65:A2:13:70:7A:7B:C5
a=setup:active
a=mid:0
a=sctpmap:5000 webrtc-datachannel 262144

Client2 Signaling

OFFER:
v=0
o=mozilla...THIS_IS_SDPARTA-68.7.0 6737140054204525907 0 IN IP4 0.0.0.0
s=-
t=0 0
a=sendrecv
a=fingerprint:sha-256 2A:64:35:B7:33:86:BF:A8:D8:FF:D0:14:05:1B:AA:C6:11:9B:65:C2:EC:07:3F:CD:B3:D1:2C:13:04:37:B5:EE
a=group:BUNDLE 0
a=ice-options:trickle
a=msid-semantic:WMS *
m=application 60140 UDP/DTLS/SCTP webrtc-datachannel
c=IN IP4 68.0.149.127
a=candidate:0 1 UDP 2122252543 192.168.0.147 60140 typ host
a=candidate:3 1 UDP 2122187007 2600:8800:7900:666:428d:5cff:febc:86c4 47781 typ host
a=candidate:6 1 TCP 2105524479 192.168.0.147 9 typ host tcptype active
a=candidate:7 1 TCP 2105458943 2600:8800:7900:666:428d:5cff:febc:86c4 9 typ host tcptype active
a=candidate:1 1 UDP 1686052863 68.0.149.127 60140 typ srflx raddr 192.168.0.147 rport 60140
a=sendrecv
a=ice-pwd:8cb01e0f82513c79c7a3f719f66bef04
a=ice-ufrag:87eb786f
a=mid:0
a=setup:actpass
a=sctp-port:5000
a=max-message-size:1073741823

ANSWER:
v=0
o=AvatarChat 4 0 IN IP4 168.235.79.45
s=-
t=0 0
a=group:BUNDLE 0
m=application 60140 UDP/DTLS/SCTP webrtc-datachannel
c=IN IP4 168.235.79.45
a=candidate:udpcandidate 1 UDP 1076558079 168.235.79.45 44352 typ host
a=candidate:tcpcandidate 1 TCP 1076302079 168.235.79.45 55470 typ host
a=ice-ufrag:8h6be6aljaxvo6wu
a=ice-pwd:li3g3zva0v6k935v6nk9sk0fp8fhekeo
a=ice-lite
a=end-of-candidates
a=fingerprint:sha-1 37:1E:2F:18:8B:93:7E:7A:61:F3:E7:57:85:BB:31:50:FA:40:5F:DF
a=fingerprint:sha-224 D4:08:62:AA:7E:02:13:E4:8E:76:D0:5E:15:5F:5B:86:9E:B8:D8:22:7E:B7:EA:12:61:45:4F:CB
a=fingerprint:sha-256 02:A3:F2:BE:7B:12:9E:9E:79:5F:FE:26:9A:C9:DB:58:38:59:AC:12:81:4B:BE:C2:C3:99:30:18:D0:EE:80:8D
a=fingerprint:sha-384 96:E5:19:72:AD:3E:9C:F3:D9:40:A6:92:AE:2B:E9:E8:FB:92:06:2D:FE:B8:DB:61:DB:A4:74:13:EF:04:79:64:74:E7:14:D9:99:1D:6E:A7:5B:B3:E3:CD:15:C6:50:EA
a=fingerprint:sha-512 BF:9D:DA:55:76:8C:01:DB:8C:D6:DB:CD:0A:49:5D:D4:23:93:97:BA:E5:08:2E:92:9F:E1:41:75:85:4C:42:93:08:0E:40:B1:65:F2:6B:45:CF:E2:3D:28:DA:92:CC:52:44:84:73:65:60:40:E5:47:3C:65:A2:13:70:7A:7B:C5
a=setup:active
a=mid:0
a=sctpmap:5000 webrtc-datachannel 262144

Client 3 Signaling:

v=0
o=mozilla...THIS_IS_SDPARTA-68.7.0 8822641039952135555 0 IN IP4 0.0.0.0
s=-
t=0 0
a=sendrecv
a=fingerprint:sha-256 D4:4E:16:B4:46:41:6C:62:8F:56:7A:A7:79:DA:24:43:81:4C:5D:60:59:D9:45:0C:BC:70:72:78:E9:5C:81:24
a=group:BUNDLE 0
a=ice-options:trickle
a=msid-semantic:WMS *
m=application 53492 UDP/DTLS/SCTP webrtc-datachannel
c=IN IP4 68.0.149.127
a=candidate:0 1 UDP 2122252543 192.168.0.147 53492 typ host
a=candidate:3 1 UDP 2122187007 2600:8800:7900:666:428d:5cff:febc:86c4 35260 typ host
a=candidate:6 1 TCP 2105524479 192.168.0.147 9 typ host tcptype active
a=candidate:7 1 TCP 2105458943 2600:8800:7900:666:428d:5cff:febc:86c4 9 typ host tcptype active
a=candidate:1 1 UDP 1686052863 68.0.149.127 53492 typ srflx raddr 192.168.0.147 rport 53492
a=sendrecv
a=ice-pwd:7440d4cb78ffebc44f70b0fe26f28349
a=ice-ufrag:2997f756
a=mid:0
a=setup:actpass
a=sctp-port:5000
a=max-message-size:1073741823


ANSWER:
v=0
o=AvatarChat 11 0 IN IP4 168.235.79.45
s=-
t=0 0
a=group:BUNDLE 0
m=application 53492 UDP/DTLS/SCTP webrtc-datachannel
c=IN IP4 168.235.79.45
a=candidate:udpcandidate 1 UDP 1076558079 168.235.79.45 31360 typ host
a=candidate:tcpcandidate 1 TCP 1076302079 168.235.79.45 41295 typ host
a=ice-ufrag:kvaktjdrqjc1o047
a=ice-pwd:d8fpu0683cdep1d4ed46vlbx41ibeyy5
a=ice-lite
a=end-of-candidates
a=fingerprint:sha-1 37:1E:2F:18:8B:93:7E:7A:61:F3:E7:57:85:BB:31:50:FA:40:5F:DF
a=fingerprint:sha-224 D4:08:62:AA:7E:02:13:E4:8E:76:D0:5E:15:5F:5B:86:9E:B8:D8:22:7E:B7:EA:12:61:45:4F:CB
a=fingerprint:sha-256 02:A3:F2:BE:7B:12:9E:9E:79:5F:FE:26:9A:C9:DB:58:38:59:AC:12:81:4B:BE:C2:C3:99:30:18:D0:EE:80:8D
a=fingerprint:sha-384 96:E5:19:72:AD:3E:9C:F3:D9:40:A6:92:AE:2B:E9:E8:FB:92:06:2D:FE:B8:DB:61:DB:A4:74:13:EF:04:79:64:74:E7:14:D9:99:1D:6E:A7:5B:B3:E3:CD:15:C6:50:EA
a=fingerprint:sha-512 BF:9D:DA:55:76:8C:01:DB:8C:D6:DB:CD:0A:49:5D:D4:23:93:97:BA:E5:08:2E:92:9F:E1:41:75:85:4C:42:93:08:0E:40:B1:65:F2:6B:45:CF:E2:3D:28:DA:92:CC:52:44:84:73:65:60:40:E5:47:3C:65:A2:13:70:7A:7B:C5
a=setup:active
a=mid:0
a=sctpmap:5000 webrtc-datachannel 262144

My thoughts in english are: 'for every new transport that connects, make a new producer on the router. Each existing transport should consume this new producer. This new transport should consume all existing producers." - to me, this sounds like a “conference room” setup, but with datachannels.

Expected behavior:
As each new peer connects, they are ‘added’ to the room of interconnected producers&consumers

Actual behavior:
Two peers communicate correctly, but the third peer added only receives data from the first peer. No peers receive data from the third peer.

Interpretation:
Whew, this has been giving me a headache for a few days… The connections to the mediasoup client are correct in that they establish a connection. It could be my SDP conversions to ORTC which I am doing manually but believe I have the understanding to relay one stream for the datachannel. I’m passing the m=application string back to the client, with 5000 as the ‘cosmetic’ port number. I see in the client and libmediasoup libraries there are restrictions based on design about one-way data pipes. but I’m not using either. This is mediasoup nodejs module. I check the transports, and it seems that all the consumers and producers are registered. I have also seen that some streams require to be paused until connected, but the dataproducer has no pause attribute. Also, it may be that there is special magics on local connections that make ice confused.
I feel like it somewhere in the sctp(datachannel sctreamid) muxing getting confused with how I have it setup, or I’m somehow blocking other consumers from consuming…
I have looked at pipeToRouter and such, but it seems that is for transmitting to another router, not what I want.
This behavior might make sense if producers and consumers replaced each other… but I don’t believe thats how it works in mediasoup.
I suppose my real question is: “If it works for two peers on the local network, why does the Nth peer after 2 only get the 1st peers data?”

Any help or nudges in the right direction would be greatly appreciated. I realize that I can use mediasoup client with data channels one way, but am very stubborn and hope to make multiple clients talk over one webrtcdatachannel.

Advice that I am just looking at all ths the wrong way is welcome too, just to be open minded. :smiley:

You cannot use id:0, it’s reserver.

Regarding the rest of your topic, I’m afraid it’s too long and it does not even use mediasoup-client which comes with a proper API to deal with mediasoup DataProducers and DataConsumers. It seems that you are building a client app on your own, but I’m afraid I don’t have time to explain the mediasoup-client internals.

Just a few comments:

  • In mediasoup, a DataProducer is a DataChannel just for sending messages from client to server.
  • In mediasoup, a DataConsumer is a DataChannel just for receiving messages from a specific DataProducer.
  • In pure WebRTC a DataChannel is bidirectional, but we do a different thing in mediasoup because, at client side, we separate sending transports and receiving transports (for both, audio/video and data).
  • If client A creates DataProducer_A and you want to receive those messages in client B and C, you must create two DataConsumer to consume DataProducer_A (in client side and server side): one for client B and another one for client C.

In addition: you SHOULD NOT build your server app using router.observer.on(xxx) or any other xxx.observer. Observers are just supposed for monitor libs on top of mediasoup. If you create a transport in server side you know that you have created it, so do not rely on any “observer” event to tell you that. You already know that you have created a transport.

Wow, thanks for quick answer!

If I am unable to use bidirectional data over a datachannel, I may have to change my setup and use a channel for each peer. That may be the push I needed just to use mediasoup client.

Doh! I didn’t realize 0 was reserved. That is good to know.

Yes, I wanted to use a pure javascript client and not the mediasoup client, because of the requirement to split data channels. But I leaned from you today that the server still needs to have it split still. I agree, dont waste your time explaining the internals of the mediasoup client. I think you have given me the information I need. Thank you.

I will redesign my client app a bit to use mediasoup-client, since I still must use datachannels the mediasoup way.

I will no longer use the observer patterns, thank you for the insight.

Whew, thank you for setting me back on the right track here, and making mediasoup.

1 Like

The server does not require “separate Datachannels for sending and receiving”. It’s just that mediasoup is more low level than the WebRTC Datachannel API and works at SCTP level in which there is no reason to mandate creating SCTP channels with same id for sending and receiving.

The client decides the SCTP id of the DataProducer. However it’s mediasoup who decides the SCTP id of a DataConsumer, and it’s random.

1 Like