Hi, it's Hello everyone.
The next talk is actually for me about how Mr.
For Handles SRT connections in the Ben and Shell processes.
This is actually a bit of a hack that we did in the past few months
to make something that we wanted to work work
and I figured it would be interesting to share
because SRT is a common political to share media over.
For reference, I am the lead of the Mr. for Team.
For context, we need to first go over what is Mr. for exactly
otherwise the rest of this talk won't make sense.
I'll try to keep this short.
Mr. for is a media server software package that's been
development for about 16 years or so.
It's a free and open source.
In license, we have only one edition, the free one,
and that's it, and everything is completely open.
The focus on transmuxing and easy integration
which means it's very developer-centric.
So that means that it is something that takes media feeds.
We focus mostly on transmuxing meaning that we don't do
encoding though we can but we prefer not to.
And we take things in any protocol and send it to any protocol.
With a focus on if you want to put this in some other system,
well, then this is the tool you would use.
A more interesting thing that we need to go a little bit
in depth in is that this uses a separate process for every connection.
In going out going, it doesn't matter.
Every connection, a separate process.
This is less efficient and web servers stop doing this,
like I think 20, 30, maybe more years ago.
But while you're redoing this, because with media,
you don't really get all that many connections on a single machine.
Like most servers have maybe a gigabit of internet.
That means that if you do in this level of quality,
five hundred users and your connection is full.
So the CPU is usually kind of bored on the media server.
It's usually the network charge that is working itself.
That the CPU is kind of bored, the ram is kind of bored.
So we don't actually need to be super efficient with the CPU.
And why would we opt for this?
Because it gets us better isolation between clients.
So each of these inputs, each of these outputs,
they have a separate process running.
So this is not the threat, this is not a sub-task or anything.
This is like an actual separate program running handling that connection.
That gives us very good isolation in the sense that if someone's doing something weird,
it's a RTP input or something and they're trying to catch the server,
they can catch their own connection, but they can't catch anyone else's.
So this is a property that we really really like.
But there is a problem with this property.
Because a couple of years ago, back in 2012,
a high-vision created a protocol called SRT, secure reliable transport.
Not to be confused with SRT the sub-title format.
I don't know why they named it that either.
And this basically takes MPEC-deastreams.
And it sends them over a fancy pipe that takes care of problems on the internet.
So retransmissions, packet loss, stuff like that.
It makes sure that you have a stable feed.
It was open source in 2017.
And since then, it's really had a bit of an update in people using it.
Because the big studios in such, they generally send MPEC-deast over all kinds of connections.
And with SRT, they could start using the internet rather than cables.
And especially the fancy cables that the broadcast industry uses,
they tend to be quite expensive.
The hardware that works with them is also expensive,
hard to get, hard to maintain.
And using the internet is just kind of easier.
So these are all sounds great.
And of course, as soon as this was open source,
deep but it's in there and it works.
However, there is a small problem with it.
You would say, OK, lip uncertainty.
The reference implementation made by having it in themselves.
It's open source.
It's in C++.
Missed open source lip SRT is open source.
You can use use that right?
We technically can.
There are two other options as well.
BIP has their own implementation, called UPIMP SRT,
which is very closely tied to UPIP.
And it's not a film implementation, so we can't use that one.
And there's also GO SRT.
But it seems to have been written in a bit of a brush.
I didn't actually personally test it,
but it's also written in GO and also a partial implementation.
So we couldn't really do that with C++ for that,
going through a whole bunch of hoops.
That left lip SRT is the only viable option for using SRT.
But there's a minor inconvenience with lip SRT,
because lip SRT takes ownership of the underlying UDP tokens.
And this means that we tell lip SRT, OK,
GO boots, listen on this port, start taking connections,
and then anything that comes into that port,
it goes into that particular liability that's running,
and we no longer can do or trick where we can accept the process.
Like we're stuck using one process for everything going in or out or anywhere.
And that's kind of annoying, that means we lose our fancy advantage.
So what can we do to fix this?
Well, there are a few solutions that we've considered.
One of them would be to add support for forking different binaries to lip SRT itself.
We would either have to upstream that or fork the entire library.
We took one look at the library, and we kind of nope the out,
because especially when it was just open sourced,
the best word to describe what it looked like at the time was spaghetti.
Since then, it has improved a little.
It's definitely made big strides.
They also did all kinds of fun things like releasing the spec,
which is great, because it was spec by implementation at first,
and now it's spec by spec and implementation breaks that spec.
But it's at least at least it's there.
And so that was not really an option.
And we also think that upstream is kind of thing.
It would be kind of niche, and they probably wouldn't want it in the main library either way.
We did talk to some of the people who are high vision,
and they seem like they might be interested,
but I think that if we actually push through their interest would drop.
So the other option would be to write our own implementation.
And well, I have talked a little bit that the guys that did their own implementations.
And it seems like the takeaway from them is, please don't,
because it's kind of horrible.
So we decided not to do that either.
So then that means there's a problem, right?
We could do the modification or the forking.
We could do the production implementation.
Back when it was still open sourced initially,
we thought, hey, uncertainty, it might be fat, right?
Maybe it will go away, maybe the industry won't care,
and we can use silently ignore it.
So we did an initial solution where we did the kind of ugly thing,
and we used to use the library, and we used to use the one binary,
and all the connections go to the one binary.
And if it's precious for some reason, well, all of them used to go by by.
And we didn't like that.
This was the situation that we were like, yeah, it's probably fine, right?
But the unfortunate part is that the uncertainty actually ended up sticking around.
In fact, it got quite popular, and it is now more or less the default protocol.
For sending media over the internet for both guests and industry things.
So yeah, that's kind of a problem then, right?
We have a crappy implementation that we don't like.
Our customers don't like.
But we kind of want to improve it.
So what can we do?
So we started looking around a little bit,
and as I mentioned in a couple of slides back,
there's a pieceback that's available now.
Here we have some nice screenshots from the spec.
There we have the header.
And here we have a specifically in a handshake package,
what is in the rest of the package.
And I let it a couple of things here.
Initially in the header, there's the first four bytes.
Those mentioned what type of packet it is.
And if the control type is zero, and the sub-type is zero,
that means it's a handshake package.
But that's convenient, because that means that it's just one zero zero zero zero zero zero zero zero zero.
That's pretty easy to recognize.
We don't really care about any of the rest,
because we're not trying to implement a protocol.
We're trying to see if there's a new connection coming in, right?
Then if you have the handshake package, you can see in the type,
okay, what kind of handshake is it?
Is it a rendezvous handshake,
where we have two end points connecting to each other?
Is there a regular one where someone's connecting in?
And that brings us to an implementation that looks like this.
Check if those four bytes are that, and it's a handshake.
Check if bytes 36 to 39 are all zero,
then it's around the full packets.
That's nice and easy, isn't it?
Let's just check four bytes, check four more bytes.
So that means that we can do a nice little trick,
and we came up with this trick.
Before I go into what the exact trick is,
I need to go over UDP's sockets real quick,
because not everyone might know the fill details of those.
So I assume most people here do know that UDP is a connectionless protocol.
So if you have a UDP socket, it's not connected really.
It just sends packets, and it might receive packets,
depending on if it was bound to a port,
but that's pretty much it.
However, you can connect the UDP sockets.
So let's say that we have a socket here,
listening on genetic ports, you know,
the cache all interface on a particular port,
and people are sending data to it.
Those will come into that same socket on the system.
But if you now open a second socket,
check that to one of those endpoints by saying,
okay, we're listening on the particular interface
that's receiving those packets,
and we're going to be sending to the interface,
and the port that is sending them to us,
then this happens.
The data from that particular client will go to that socket,
well, everything else will go to the generic one.
So we can do a neat little trick,
where we listen on a generic socket.
If you see a handshake, we spawn a new process,
we create a connected socket,
and I think actually it has to be in the next slide.
Yes.
So we listen on the main port ourselves.
We intercept this, that's a very sharp joke.
We spawn a new process, if you see a handshake,
we initialize the lip-sorty library at that point
after we've already received a handshake,
and we give it the connected UDP socket
and say, here listen on this one,
this does, it's going to work out,
and guess what, it's going to see a handshake packet,
because those handshake packets get repeated a whole bunch of times.
So, you know, we purposely dropped the first one,
but it's going to see a handshake packet.
And it's going to be like, oh hey, a handshake packet,
and it will accept that one connection,
and it will never see another connection in its life
because that's a connected socket.
So it will only see that one user.
And the lip-sorty documentation actually explicitly states
that you should not and cannot do this.
But if you do it, totally works.
And I checked with the original author of SRT,
and he said it should be fine.
So that kind of works.
And then we get our nice little trick,
where we can get a standard,
unemodified version of lip-sorty,
and we get notic losses isolation
and kind of the best of both worlds.
We can listen on a generic port,
spawn notable processes all we want,
and none of them catching will hurt the others,
and we get normal SRT connections
without having to rewrite everything from scratch.
And that's the magical little trick that I wanted to show here.
Which makes me to the end of the presentation.
I think I went through it quite fast.
Yeah, not too bad.
So now we have a questions.
Are there any?
Thank you.
So are you just dropping the first handshake packet?
So when you're receiving that and the clients and another one?
I'll repeat the question, Craig,
so that the people mostly know what you asked.
The question was, do we drop the first handshake packet
and expect the other side to send another one?
Yes, absolutely.
We actually looked and the SRT's packet,
it sends approximately 50 or 60 handshake packets in the first seconds.
It's dropping the first one.
It doesn't really hurt the connection.
We could do a fancy thing where we tell the library
that we saw the packet or we fake one,
but we found it was not necessary and just made it
necessarily complex.
So we kind of stuck with that implementation.
Anyone else?
Yeah, go ahead.
So the question is, does this work with not-deplexing
where you have multiple clients sending on the same port
and all going to a different stream ID?
Yes, that is the whole reason we did this.
So that we could have one port and we could send
dozens of different streams in or out over the same port
and they would not bother each other.
That's the whole idea behind it.
Yep, absolutely.
Anyone else?
Yeah, go ahead.
So the does is mean that
this server is always
missing for
up for
a server always try to look for
as our
team
con
even when you're not
using a server.
So good question.
It is, it's a server always
listening for
SD connections even if you're not using a
SD.
It depends.
You can configure a
miss to listen on one or more
SD ports and you can
discard ones.
And if you do that,
it will listen.
And if you don't
configure that, it will not.
Simple as that.
Anyone else?
Yeah?
Okay.
Well, then I guess that was it.
If you want to find out more about
miss server,
visit us,
miss server.org or
skim.gov.
You can also send me
personally an email or
info of miss server
if you want to team.
We hope to hear from you
if you're interested.
All right.
Thanks for your attention.