I appreciate the debugging support.
Let me preface that we’ve been sending simulcast RTP + RTCP streams into mediasoup successfully for weeks. We can see all of the spatial layers, and the consumer can adjust them on the fly, as well as the system does detect any delays or packet loss and selects the appropriate layer automatically.
That all works. Kudos!!
Our “broadcast” is performed by first opening up a room using the demo app, so we have a room already established, then we go through the handshake over REST to set up the broadcast ports and send it along for the ride.
Our broadcast is generated using gstreamer as an outside source, very similar to your gstreamer.sh example, but a bit more robust.
This too all works flawlessly.
Finally, before I provide this information based on your debugging advice (which is a work in progress), I want to be clear we’re not saying there’s a bug within mediasoup. There may simply be a behavior that works one particular way, and we’re trying to understand it in the event we want to tune it to our specific needs.
By setting the logLevel and logTags accordingly, we did see some interesting information.
I do believe the information is enlightening however…
For our test, we’re only interrupting one of the streams - we send 4 of them…
A multiplexed Video RTP stream (0), with each stream having a separate SSRC.
A Video RTCP stream (1), also multiplexed for each SSRC.
A non-multiplexed Audio RTP stream (2)
A companion Audio RTCP stream (3).
So we use 4 ports that are typical in this setup.
Again, these all work exactly as expected…until we sever the connection…for this experiment, we only broke the connection for stream 0 - which means the Video RTCP stream remained in tact along with the Audio streams.
On initial transmission, we see the following…
mediasoup:Channel [pid:27541] RTC::PlainTransport::OnRtpDataReceived() | setting RTP tuple (comedia mode enabled) +2s
mediasoup:Channel [pid:27541] RTC::Producer::CreateRtpStream() | [encodingIdx:1, ssrc:2221, rid:, payloadType:96] +0ms
mediasoup:Channel [pid:27541] RTC::Producer::CreateRtpStream() | DTX enabled +0ms
mediasoup:Channel [pid:27541] RTC::Producer::CreateRtpStream() | [encodingIdx:0, ssrc:2220, rid:, payloadType:96] +0ms
mediasoup:Channel [pid:27541] RTC::Producer::CreateRtpStream() | DTX enabled +0ms
mediasoup:Channel [pid:27541] RTC::Producer::CreateRtpStream() | [encodingIdx:2, ssrc:2222, rid:, payloadType:96] +1ms
mediasoup:Channel [pid:27541] RTC::Producer::CreateRtpStream() | DTX enabled +0ms
mediasoup:Channel [pid:27541] RTC::Producer::CreateRtpStream() | [encodingIdx:3, ssrc:2223, rid:, payloadType:96] +0ms
mediasoup:Channel [pid:27541] RTC::Producer::CreateRtpStream() | DTX enabled +0ms
Looks good.
On intentional break of stream 0…
mediasoup-demo-server:Room transport "trace" event [transportId:d9b5a7cf-8a68-402b-b09f-df2c575abd91, trace.type:bwe, trace:{ direction: 'out', info: { availableBitrate: 5400000, desiredBitrate: 4000000, effectiveDesiredBitrate: 4000000, maxBitrate: 5400000, maxPaddingBitrate: 4590000, minBitrate: 30000, startBitrate: 5400000, type: 'transport-cc' }, timestamp: 2782941264, type: 'bwe' }] +184ms
mediasoup:WARN:Channel [pid:27541] RTC::RtpStreamRecv::OnTimer() | RTP inactivity detected, resetting score to 0 [ssrc:2222] +2m
mediasoup:WARN:Channel [pid:27541] RTC::RtpStreamRecv::OnTimer() | RTP inactivity detected, resetting score to 0 [ssrc:2223] +1ms
mediasoup:WARN:Channel [pid:27541] RTC::RtpStreamRecv::OnTimer() | RTP inactivity detected, resetting score to 0 [ssrc:2221] +0ms
mediasoup:WARN:Channel [pid:27541] RTC::RtpStreamRecv::OnTimer() | RTP inactivity detected, resetting score to 0 [ssrc:2220] +0ms
mediasoup-demo-server:Room protoo Peer "request" event [method:getTransportStats, peerId:wr1eqafd] +2s
As expected…
Now, resuming the stream is not starting the stream over, it’s simply us allowing the data to flow again - the source streams have not stopped…so any timing or sequence numbers in the RTP and RTCP packets should be aligned.
After resuming stream 0 (allowing it to flow to the port again), we see this output flying up the screen, it literally overtakes the debug output and continues infinitely until the room is destroyed…
mediasoup:Channel [pid:27541] RTC::PlainTransport::OnRtpDataReceived() | ignoring RTP packet from unknown IP:port +0ms
mediasoup:Channel [pid:27541] RTC::PlainTransport::OnRtpDataReceived() | ignoring RTP packet from unknown IP:port +0ms
mediasoup:Channel [pid:27541] RTC::PlainTransport::OnRtpDataReceived() | ignoring RTP packet from unknown IP:port +0ms
mediasoup:Channel [pid:27541] RTC::PlainTransport::OnRtpDataReceived() | ignoring RTP packet from unknown IP:port +0ms
mediasoup:Channel [pid:27541] RTC::PlainTransport::OnRtpDataReceived() | ignoring RTP packet from unknown IP:port +0ms
mediasoup:Channel [pid:27541] RTC::PlainTransport::OnRtpDataReceived() | ignoring RTP packet from unknown IP:port +0ms
That’s really interesting, as we don’t use the data channel at all, and we’ve not renegotiated anything - we’ve just interrupted the Video RTP output going to the inbound mediasoup port (in this case 46565) for about 8 seconds. All the other streams were flowing.
Incidentally, if we turn dtx off, and we stop the stream for just 1 second, and restart, the same thing happens.
So I think I may know what’s causing this, so let me explain and maybe you can help me understand if there are any configuration options we should examine…
In the evolution of our system, we’ve introduced a middleware server that handles some stream negotiations…
Our source stream is at location A which streams into our middleware, and then the middleware takes the stream and send it to B (mediasoup).
In our “disconnect” operation, we sever the B side - so it goes from gstreamer into A, then A to B, then B to mediasoup, and we temporarily shut down B (although we’ve also done this test shutting down the A side).
So for example…
Let’s say we took stream 0, and we piped that into port 39000, which sends to to our middleware on port 3900, and then our middleware takes the stream and sends it to Port X on mediasoup.
My guess is if we shut down our A side or B side, they renegotiate, and by doing so, the connection on the B side to Port X is a different source port. It’s the same IP, it’s the same destination (Port X), but because A reconnects to B, we don’t force our “source port” a certain way, so when the stream continues to Port X our IP:source port combination is different.
That would explain why it doesn’t pick up the stream. It stops it in its tracks.
Sounds like to resolve this issue, we need to fix our source port side on the B side.